1

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)) == trueGetEntity(key).Equals(obj) == true. 私は何を間違っていますか?

私は.Mergeを使用したくありません。アプリケーションでは、どのオブジェクトもセッションでクローンを持つことができるため、すべてのSaveOrUpdateをMergeに変更する必要があることを意味します。

更新。私が SaveOrUpdate しようとしているオブジェクトには、双方向の多対多として別のオブジェクトがあります。そのため、NHibernate はオブジェクト ツリーをたどり、my object-> another object that many-to-many->に移動し、1 番目と 2 番目が参照によって等しいmy objectにもかかわらず、失敗します。my objectmy object

4

1 に答える 1

1

Hibernate はそこで等しいチェックを行う必要はありません。StatefulPersistenceContext.GetEntry()null が返されたため、指定されたエンティティがセッションにないことは既にわかっています。参照の等価性によってエントリを検索するため、null が返されました。したがって、セッション内の他のオブジェクトが指定されたものと同じ Id を持っている場合、ドキュメントに従うために例外をスローする必要があります。

等しい 2 つのオブジェクトが同じである必要はありません。「同じ」は、通常、2 つの参照が同じオブジェクトを指している (参照が等しい) という意味で使用されます。

PS: あなたの質問とは関係ありませんが、Equals実装は継承マッピングを使用するエンティティのプロキシを比較するのに安全ではないようです (プロキシは基本クラスのみを継承するため、継承されたクラスには割り当てられません)。

于 2013-06-25T09:08:41.423 に答える