我无法理解它抛出NonUniqueObjectException的原因。 NHibernate文档明确指出:
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用于另一个场景,对我的情况总是为null):
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
通过引用相等,也会失败!
答案 0 :(得分:1)
NHibernate不必在那里做同等检查。它已经知道给定的实体不在会话中,因为StatefulPersistenceContext.GetEntry()
返回null。它确实返回null,因为它通过引用相等性搜索条目。因此,如果会话中的任何其他对象具有与给定ID相同的Id,则必须抛出异常以遵循文档。
两个相等的对象不必相同。 “相同”通常用于表示两个引用指向同一个对象(引用相等)。
PS:与您的问题无关,但似乎您的Equals
实现对于比较使用继承映射的实体的代理是不安全的(代理只继承基类,因此它不能分配给继承的类)。