1

Nameインスタンスを一意に識別するために使用されるメンバーを持つ単純なクラスがあります。Nameこのクラスは、 (主キーであるため) を使用してマッピング テーブルを作成するManyToMany マッピングで参照されます。関連する文字列のタイプにより、これは非常に遅くなります (長さ > 128 文字、多くの場合、最後の数文字だけが異なります)。高速化するために、結合用の列 (私は MySQL を使用しています) を作成したいと思いますauto_incrementが、-column を使用して nhibernate でオブジェクトの一意性を並べ替えることができますName

これがどのように見えるかの例です。実際には、オブジェクトははるかに大きくなります。

class MyObject{
  public String Name;
  public String Value;
}
//Mapping
Id(x => x.Name)
  .Length(255)
  .Unique();
Map(x => x.Value);

これは意図したとおりに機能します。テーブルに新しいものを追加するMyObjectと、nhibernate は最初に選択を行い、同じレコードNameが既にテーブルにあるかどうかを確認します。

ObjectHolderのセットを持つ がありますMyObject

class ObjectHolder{
  public UInt64 Id;
  public ICollection<MyObject> MyObjects;
}
//Mapping
Id(x => x.Id)
  .GeneratedBy.Native();
HasManyToMany(x => x.MyObjects)
  .AsSet()
  .Cascade.SaveUpdate();

ObjectHolder.Idこれにより、 と を使用してマッピングが作成されますがMyObject.Name、これは低速です。自動生成され、マッピングテーブルにのみ使用される Id 列が必要ですMyObjectが、nhibernate が主キーで行う、存在するかどうかを確認するためのチェックには使用されません。

マッピングを次のように変更しました

class MyObject{
  public UInt64 Id;
  public String Name;
  public String Value;
}
//Mapping
Id(x => x.Id)
  .GeneratedBy.Native();
Map(x => x.Name)
  .Length(255)
  .Unique();
Map(x => x.Value);

Nameこれにより、auto_increment カラムが作成され、マッピング テーブルに使用されますが、同じレコードが既に存在するかどうかが正しくチェックされなくなり、エントリの重複例外が発生します。

nhibernate にName、id の代わりに列をチェックするように指示したり、 -column に注釈を付けてId、外部キーとしてのみ使用されるようにすることはできますか? manyToMany マッピングを変更する必要がありますか?

編集:複合IDを使用する必要がある場合はさらに悪いようです。すべての id プロパティは、オブジェクト自体に 1 回、マッピングに 1 回、合計 2 回保存されるため、時間とストレージ スペースのオーバーヘッドが大幅に増加します。

4

1 に答える 1

1

あなたはこの問題を間違った方法で見ています.NHは、それがすでに存在するかどうかを確認することを想定していません. すでに存在するかどうかを知る必要があります。

名前が一意かどうかを確認することは、検証とビジネス ロジックの一部である必要があります。そのため、保存する前に名前が使用されているかどうかを確認する必要があります。

自分でデータベースにアクセスしていた場合は、制約違反を処理できたはずです。ただし、バッチ処理が複雑になるため、NHibernate はこれをサポートしていません。つまり、トランザクションがフラッシュされたときにバッチが保存され、エンティティを永続化した場所ではなく、エラーが発生したポイントになります。したがって、NH ができる唯一の賢明なことは、トランザクション全体をロールバックしてエラーをスローすることです。

基本的に、データベースの制約は、ビジネス ルールをチェックするために依存するものではなく、無効なデータを防ぐための最終的なフェールセーフにすぎません。

于 2012-10-01T00:58:05.157 に答える