Я думаю, что Объекты должны реализовать равенство по сравнению первичного ключа как значение по умолчанию, но nhibernate документация рекомендует использовать бизнес-идентификационные данные:
Самый очевидный путь состоит в том, чтобы реализовать, Равняется ()/GetHashCode () путем сравнения значения идентификатора обоих объектов. Если значение является тем же, оба должны быть той же строкой базы данных, они поэтому равны (если оба будут добавлены к ISet, то у нас только будет один элемент в ISet). К сожалению, мы не можем использовать тот подход. NHibernate только присвоит значения идентификатора объектам, которые постоянны, недавно созданный экземпляр не будет иметь никакого значения идентификатора! Мы рекомендуем реализовать, Равняется () и GetHashCode () использование Бизнес-ключевого равенства.
Бизнес-ключевое равенство означает, что Равняние () метод сравнивает только свойства, которые формируют бизнес-ключ, ключ, который определил бы наш экземпляр в реальном мире (ключ наиболее подходящего кандидата)
И пример (также из документа):
public override bool Equals(object other)
{
if (this == other) return true;
Cat cat = other as Cat;
if (cat == null) return false; // null or not a cat
if (Name != cat.Name) return false;
if (!Birthday.Equals(cat.Birthday)) return false;
return true;
}
Это получило мою голову, вращающуюся, потому что понятие бизнес-идентификационных данных (согласно примеру) совпадает со сравнением синтаксисом, который является в основном типом семантики, которую я связываю с ValueObjects. Причина того, что не использовались первичные ключи базы данных в качестве сравнительных значений состоит в том, потому что это изменит хэш-код объекта, если первичный ключ не будет сгенерирован на стороне клиента (для исключая возрастающим), и Вы используете своего рода набор хеш-таблицы (такой как ISet) для хранения Ваших объектов.
Как я могу создать хорошую реализацию равенства, которая не нарушает общие правила для равенства/хэш-кода (http://msdn.microsoft.com/en-us/library/bsc2ak47.aspx) и соответствует правилам nhibernate также?
Это известная проблема с ORM. Здесь я описываю решения, о которых я знаю и даю несколько указателей.
1 Суррогатный / первичный ключ: автоматически генерируется
, как вы упоминали, если объект не был сохранен, это не работает.
2 Суррогатный / первичный ключ: присвоенное значение
Вы можете решить назначить значение PK в коде, таким образом, этот объект всегда имеет идентификатор и может использоваться для сравнения. См. Не позволяйте гибернации украсть вашу личность .
3 Натуральный ключ
Если объект имеет еще один натуральный ключ, кроме первичного ключа, вы можете использовать этот. Это было бы в случае для клиентского объекта, который имеет числовой первичный ключ и Номер клиента строки. Номер клиента идентифицирует клиента в реальном мире и является естественным ключом, который не изменится.
Возможен 4 значения объекта
, используя значения объектов для равенства. Но есть ли другие недостатки, вы упомянули. Это может быть проблематично, если значения изменения, и объект находится в коллекции . Например, если у вас есть SET
с двумя объектами, которые были сначала разные, но затем вы изменяете значения, когда они ссылаются на набор, чтобы они стали равными. Затем вы нарушаете договор набора
. См. Hibernate равна и Hashcode .
5 Смешанные: значение + Автогената Первичные / суррогатные клавиши
Если объекты сравнения уже имеют идентификатор, используйте его. В противном случае используйте значения объекта для сравнения.
У всех есть некоторые плюсы и минусы. ИМХО, лучшее - это 3, если это возможно с вашей моделью домена. В противном случае я использовал 5, и он работал, хотя при использовании коллекций все еще есть какая-то ловушка. Я никогда не использовал 2, но это звучит также разумное решение, если вы найдете способ генерировать PK в коде. Может быть, другие у людей есть указатели для этого.