2

GetHashCode()ID 列を持つ NHibernate エンティティを適切に実装することは不可能であるという結論に達しました。私が見つけた唯一の実用的な解決策は、定数を返すことです。説明については、以下を参照してください。

これは明らかにひどいことです。すべての辞書検索は実質的に直線的になります。私が間違っている?私が見逃した回避策はありますか?

説明

次のような 1 つ以上の Product エンティティを参照する Order エンティティがあるとします。

class Product
{
    public virtual int Id { get; set; } // auto; assigned by the database upon insertion
    public virtual string Name { get; set; }
    public virtual Order Order { get; set; } // foreign key into the Orders table
}

「Id」は、SQL Server 用語でIDENTITY列と呼ばれるもので、レコードが挿入されたときにデータベースによって自動的に生成される整数キーです。

さて、実装するためにどのようなオプションがありますProduct.GetHashCode()か? 私はそれを基にすることができます

  • Id価値
  • Name価値
  • 製品オブジェクトの ID (デフォルトの動作)

これらのアイデアはどれも機能しません。Id に基づいてハッシュ コードを作成すると、オブジェクトがデータベースに挿入されるときに変更されます。以下は、少なくとも NHibernate.SetForNet4 が存在する場合に壊れることが実験的に示されています。

/* add product to order */

var product = new Product { Name = "Sushi" }; // Id is zero
order.Products.Add(product); // GetHashCode() is calculated based on Id of zero
session.SaveOrUpdate(order); 

// product.Id is now changed to an automatically generated value from DB
// product.GetHashCode() value changes accordingly
// order.Products collection does not like it; it assumes GetHashCode() does not change

bool isAdded = order.Products.Contains(product); 

// isAdded is false; 
// the collection is looking up the product by its new hash code and not finding it

GetHashCode()オブジェクト ID に基づく (つまり、デフォルトの実装のままにProductする) こともうまく機能しません。これは以前に StackOverflow で取り上げられました。変更可能な場合、に基づくGetHashCode()ことNameは明らかに良い考えではありませんName

それで、何が残っていますか?私のために働いた唯一のことは

class Product
{
    ...
    override public GetHashCode() { return 42; }
}

この長い質問を読んでくれてありがとう。 それをより良くする方法について何かアイデアはありますか?

PS。これは NHibernate に関する質問であり、コレクションに関する質問ではないことに注意してください。コレクションの型と操作の順序は任意ではありません。それらは、NHibernate の動作方法に関連付けられています。たとえば、単純に Order.Products を IList のようなものにすることはできません。インデックス/順序列が必要になるなど、重要な意味があります。

4

1 に答える 1

2

Id に基づいてハッシュコード (および明らかに等価) を作成します。これは正しいことです。問題は、オブジェクトが Dictionary にある間に Id を変更したことに起因します。オブジェクトは、辞書またはハッシュセット内にある間、ハッシュコードと等価性に関して不変でなければなりません。

2 つのオプションがあります -

  1. 項目を DB に格納する前に辞書やハッシュセットを設定しないでください
  2. オブジェクトを DB に保存する前に、辞書から削除してください。それをDBに保存してから、辞書に再度追加してください。

アップデート

この問題は、他のマッピングを使用して解決することもできます

  1. バッグ マッピングを使用できます。これは IList にマップされ、問題なく動作するはずです。HashSets や Dictionaries を使用する必要はありません。
  2. DB スキーマが管理下にある場合は、インデックス列を追加して関係を順序付けることを検討してください。これは再び IList にマップされますが、リスト マッピングがあります。

マッピングとシナリオに応じて、パフォーマンスに違いがあります ( http://nhibernate.info/doc/nh/en/#performance-collections-mostefficientupdateを参照) 。

于 2013-08-22T19:12:57.843 に答える