2009-04-08 2 views
1

Я переопределял Equals и GetHashCode в абстрактном базовом классе для реализации равенства значений на основе свойства ключа объекта. Моя основная цель - использовать метод Contains для коллекций вместо Find или FirstOrDefault, чтобы проверить, был ли экземпляр уже добавлен в коллекцию.Сравнение значений равенства по новым объектам

public abstract class Entity 
{ 
    public abstract Guid Id { get; } 

    public override bool Equals(object obj) 
    { 
     if (obj == null) 
     { 
      return false; 
     } 

     if (obj.GetType() != GetType()) 
     { 
      return false; 
     } 

     var entity = (Entity)obj; 
     return (entity.Id == Id); 
    } 

    public override int GetHashCode() 
    { 
     return Id.GetHashCode(); 
    } 

} 

Проблема такого подхода заключается в том, что все мои объекты равны перед они были сохранялось и приобрели Id (порожденную NHibernate). Я делаю это неправильно? Я мог бы сгенерировать Id в конструкторе, но я хотел бы реализовать тот же шаблон для других проектов, которые используют int id, так что, очевидно, это не сработает.

Мне кажется, что любой объект, который переопределяет Equals, будет равен любому другому экземпляру того же объекта сразу после создания объектов.

Edited добавить: Вот сценарий, который касается меня: В методе Add для моей коллекции, я проверяю, чтобы убедиться, что коллекция уже не содержит объект, который будет добавлен. Если все новые объекты были равны, то я никогда не смогу добавить в коллекцию два новых объекта.

ответ

2

NHibernate gurantees, что идентификатор объекта, связанный с объектами, связанный с тем же контекстом, совпадает с идентификатором базы данных. Поэтому нет необходимости переопределять Equals() и GetHashCode(), потому что это тот же идентификатор, который вы хотите реализовать.

См. 10.3. Considering object identity of NHibernate Reference Documentation.

Кроме того, объединение нового объекта с использованием сгенерированных с помощью ключей ключей с контекстом должно обязательно сохранять сущность в базе данных и устанавливать ключ объекта в сгенерированный ключ.

+0

Хороший вопрос ... Я не думаю, что буду хранить ссылки на коллекции между ISessions. –

1

Вы должны получить свой идентификатор или, по крайней мере, какой-то идентификатор, в конструкторе.

Если идентификатор не установлен (или является значением по умолчанию); очевидно, что метод Equals вернет true для любого объекта того же типа (который также не установил ID).

+0

Это было не очевидно для меня, пока я не попробовал, спасибо. –

0

Может ли это помочь, если вы вернете «не равный», если идентификатор не инициализирован?

public override bool Equals(object obj) 
{ 
    if (obj == null) 
    { 
     return false; 
    } 

    if (obj.GetType() != GetType()) 
    { 
     return false; 
    } 

    var entity = (Entity)obj; 
    if ((Id == Guid.Empty) || (entity.Id == Guid.Empty)) 
    { 
     return false; 
    } 
    return (entity.Id == Id); 
} 
0

Там одна из основных деталей, что влияет на ваше решение:

... Я хотел бы реализовать тот же шаблон для других проектов, использующих Int иды ...

Обычно идентификаторы создаются в базе данных для обеспечения соответствия уникальности. Теперь, когда у вас есть GUID, вам не нужно полагаться на базу данных для генерации значения. Гарантируется, что идентификаторы GUID будут уникальными. Не следуйте шаблону по неправильным причинам :)

Итак, давайте создадим значения GUID в конструкторе - просто обязательно установите сеттер, чтобы NHibernate мог перезаписать это значение, когда он извлекает сущность из базы данных.

Кроме того, вы можете рассмотреть возможность использования COMB GUIDs, если ваш администратор базы данных касается GUID и фрагментации базы данных.