2013-06-21 5 views
0

Я просто не могу понять, почему он выбрасывает NonUniqueObjectException. Документация NHibernate четко говорится, что:NonUniqueObjectException, даже если объекты одинаковые

saveOrUpdate() does the following: 
if the object is already persistent in this session, do nothing 
if another object associated with the session has the same identifier, throw an exception 
.... 

Так он должен бросить исключение только если другой объект, связанный с сеансом имеет тот же идентификатор. Мои объекты имеют свои Equals и GetHashCode переопределена (_idCopy используются для другого сценария и всегда нуль для моего случая):

public override bool Equals(object obj) 
    { 
     return Equals(obj as SimplePersistantEqualSupported); 
    } 

    public override int GetHashCode() 
    { 
     if (_idCopy != null) 
     { 
      return _idCopy.GetHashCode(); 
     } 

     return Id.GetHashCode(); 
    } 

    public virtual bool Equals(SimplePersistantEqualSupported other) 
    { 
     if (other == null) 
     { 
      return false; 
     } 

     if (ReferenceEquals(this, other)) 
     { 
      return true; 
     } 

     if (_idCopy != null) 
     { 
      // User _idCopy instead of id. 
      if (!IsTransientIdCopy(this) && !IsTransientIdCopy(other) && Equals(_idCopy, other._idCopy)) 
      { 
       return GetType().IsAssignableFrom(other.GetType()) || 
         other.GetType().IsAssignableFrom(GetType()); 
      } 

      return false; 
     } 

     if (!IsTransient(this) && !IsTransient(other) && Equals(Id, other.Id)) 
     { 
      return GetType().IsAssignableFrom(other.GetType()) || 
        other.GetType().IsAssignableFrom(GetType()); 
     } 

     return false; 
    } 

    private static bool IsTransient(SimplePersistantEqualSupported obj) 
    { 
     return obj != null && Equals(obj.Id, default(int)); 
    } 

    private static bool IsTransientIdCopy(SimplePersistantEqualSupported obj) 
    { 
     return obj != null && Equals(obj._idCopy, default(int)); 
    } 

Я знаю, что у меня есть объект с тем же идентификатором сессии. Я работаю с отдельными объектами, и так оно и должно было быть. Но поскольку они равны - они не являются Другими объектами, они одинаковы. Когда я смотрю на источники NHibernate, я не вижу, проверить на .equals() для объектов - это просто бросает исключение, когда что-либо существует в сессии с тем же идентификатором:

public void CheckUniqueness(EntityKey key, object obj) 
    { 
     object entity = GetEntity(key); 
     if (entity == obj) 
     { 
      throw new AssertionFailure("object already associated, but no entry was found"); 
     } 
     if (entity != null) 
     { 
      throw new NonUniqueObjectException(key.Identifier, key.EntityName); 
     } 
    } 

Когда я отладки в этом Я могу обеспечить, чтобы obj.Equals(GetEntity(key)) == true и GetEntity(key).Equals(obj) == true. Что я делаю неправильно?

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

Обновление. Объект, который я пытаюсь сохранить SaveOrUpdate, имеет другой объект как двунаправленный много-ко-многим. Итак, NHibernate ходит по дереву объектов, идет my object ->another object that many-to-many ->my object, и не удается, хотя первые my object и второй my object равны по ссылке!

ответ

1

NHibernate не должен делать там равную проверку. Он уже знает, что данный объект не находится в сеансе, потому что StatefulPersistenceContext.GetEntry() возвращает null. Он действительно возвращал значение null, поскольку он ищет записи по ссылочному равенству. Поэтому, если какой-либо другой объект в сеансе имеет тот же идентификатор, что и данный, он должен выдать исключение, следуя документации.

Два одинаковых объекта не обязательно должны быть одинаковыми. «Тот же» обычно используется, чтобы сказать, что две ссылки указывают на один и тот же объект (равны ссылке).

PS: Не связано с вашим вопросом, но похоже, что реализация Equals небезопасна для сравнения прокси-объектов объектов, использующих наследование (прокси только наследует базовый класс, поэтому он не может быть назначен наследуемому классу).

+0

Спасибо, что ответили! Но я до сих пор не понимаю. Как я должен работать с отдельными объектами и хранить все объекты в отдельных экземплярах? Я, хотя Equals() решит свои проблемы, но, похоже, этого не делает. Например, в моем приложении у меня есть два представления с разными объектами, которые можно редактировать, но их деревья объектов имеют одни и те же объекты. У меня есть один вид для A и один вид для B, но они оба имеют A.C и B.C - поэтому C удваивается, и я ничего не могу с этим поделать. NHibernate удваивает объект сам по себе – Archeg

+0

@Archeg Я не понимаю, почему это проблема. На мой взгляд, вы либо хотите иметь два независимых представления (каждый со своим собственным сеансом и объектами сущности) или два связанных представления (оба используют один и тот же сеанс и объекты объекта). Опишите, что вы хотите сделать. – cremor

+0

Извините, я пропустил уведомление о вашем комментарии. По какой-то причине SO не уведомил меня по электронной почте. Мне нужно провести две сессии. Это из-за архитектуры моего приложения. Мы используем короткие сеансы и отдельные объекты.Я бы хотел изменить это, но пока у меня нет на это времени. Проблема в том, что из-за этого я ломаю странные проблемы, потому что получаю два экземпляра одного и того же объекта (потому что у меня много сеансов) – Archeg