2

私はこの質問について「全体」のインターネットを検索しましたが、かなり複雑であるため、検索するのは非常に困難です。「Fluent NHibernate Many to Many with a bridge table with extra columns」などで検索してみてください...

さて、説明を簡単にするために、参照できるいくつかのテーブルを定義しません。表: ユーザー、表: 関数、表: User_Has_Function。

1 人のユーザーは多くの関数を持つことができ、関数は多くのユーザーを持つことができます。これはブリッジ テーブル User_Has_Function にリンクされています。ブリッジ テーブルには、関係にのみ関連する追加の列があります。

とにかく、FNH にはこれに対する自動解決策がないことがわかりました。基本的には、User から User_Has_Function への 1 対多の関係と、User_Has_Function から Function への多対 1 の関係を使用する必要があるため、"[One] to [Many - Many] [One] へ」。

私はこのリンクhttp://sessionfactory.blogspot.com/2010/12/many-to-many-relationships-with.htmlのように、明らかにxmlの代わりにFNHクラスマッピングを使用して解決しました。

しかし、私は解決策に満足していません。この機能を適切に行うために、このすべての作業を手動で行う必要がありますか? また、現在のように、ブリッジ テーブルに重複を挿入します。

私の頭の中で私は何か間違ったことをしています。これに対するサポートがないとは想像できません。SaveAndUpdate() を使用するだけで、重複は挿入されず、エンティティを削除すると関係も削除され、関係が残っていない場合はエンティティ自体が削除されます。

さて、ここに私のエンティティとマッピングがあります。私は Fluent NHibernate に非常に慣れていないので、何か非常に間違ったことをしたとしても大声で叫ばないでください。:)

エンティティ:

public class XUser
{
    public virtual int Id { get; set; }
    ...
    public virtual IList<XUserHasXFunction> XUserHasXFunctions { get; set; }

    public XUser()
    {
        XUserHasXFunctions = new List<XUserHasXFunction>();
    }

    public virtual void AddXFunction(XFunction xFunction, int isActive)
    {
        var xUserHasXFunction = new XUserHasXFunction()
                                    {
                                        XUser = this,
                                        XFunction = xFunction,
                                        DeployedDate = DateTime.Now
                                    };
        XUserHasXFunctions.Add(xUserHasXFunction);
        xFunction.XUserHasXFunctions.Add(xUserHasXFunction);
    }

    public virtual void RemoveXFunction(XFunction xFunction)
    {
        var xUserHasXFunction = XUserHasXFunctions.Single(x => x.XFunction == xFunction);
        XUserHasXFunctions.Remove(xUserHasXFunction);
        xFunction.XUserHasXFunctions.Remove(xUserHasXFunction);
    }
}

public class XFunction
{
    public virtual int Id { get; set; }
    ...
    public virtual IList<XUserHasXFunction> XUserHasXFunctions { get; set; }

    public XFunction()
    {
        XUserHasXFunctions = new List<XUserHasXFunction>();
    }

    public virtual void AddXUser(XUser xUser, int isActive)
    {
        var xUserHasXFunction = new XUserHasXFunction()
                                    {
                                        XUser = xUser,
                                        XFunction = this,
                                        DeployedDate = DateTime.Now
                                    };
        XUserHasXFunctions.Add(xUserHasXFunction);
        xUser.XUserHasXFunctions.Add(xUserHasXFunction);
    }

    public virtual void RemoveXUser(XUser xUser)
    {
        var xUserHasXFunction = XUserHasXFunctions.Single(x => x.XUser == xUser);
        XUserHasXFunctions.Remove(xUserHasXFunction);
        xUser.XUserHasXFunctions.Remove(xUserHasXFunction);
    }
}

public class XUserHasXFunction
{
    public virtual int Id { get; set; }
    public virtual XUser XUser { get; set; }
    public virtual XFunction XFunction { get; set; }
    public virtual DateTime DeployedDate { get; set; }
}

マッピング:

public class XUserMap : ClassMap<XUser>
{
    public XUserMap()
    {
        Id(x => x.Id, "ID").GeneratedBy.Sequence("SEQ").Column("ID");
        Table("XUSER");
        ...
        HasMany(x => x.XUserHasXFunctions).Cascade.All();
    }
}

public class XFunctionMap : ClassMap<XFunction>
{
    public XFunctionMap()
    {
        Id(x => x.Id, "ID").GeneratedBy.Sequence("SEQ").Column("ID");
        Table("XFUNCTION");
        ...
        HasMany(x => x.XUserHasXFunctions).Cascade.All();
    }
}

public class XUserHasXFunctionMap : ClassMap<XUserHasXFunction>
{
    public XUserHasXFunctionMap()
    {
        Id(x => x.Id, "ID").GeneratedBy.Sequence("SEQ").Column("ID");
        Table("USER_HAS_FUNCTION");
        Map(x => x.DeployedDate, "DEPLOYED_DATE");

        References(x => x.XUser).ForeignKey("XUSER_ID").Cascade.SaveUpdate();
        References(x => x.XFunction).ForeignKey("XFUNCTION_ID").Cascade.SaveUpdate();
    }
}
4

3 に答える 3

1

「本当にこの手作業をすべてやらなければならないのですか」という部分がわかりません。「このすべての手作業」とは何ですか?そこには特別なことは何もありません。マッピングは単純で、C# コードは永続性に関して何もする必要はありません。これは単純な古い OO 設計です。

行が重複している場合は、マッピングに問題があります。逆としてマップされていない逆コレクションが原因である可能性があります。

関数からユーザーに移動する必要がない場合は、非常に簡単です。ブログで説明されているように、関係をエンティティとしてマップするか、さらに簡単に複合要素としてマップします。

(すみません、私はFluentを知りません)

<bag name="Functions" table="User_Has_Function">
  <key column="UserId" />
  <composite-element>
    <many-to-one class="Function"/>
  </composite-element>
</bag>

編集:

コメントから:

私が話している手作業とは、ユーザーまたは関数から関係を削除および追加するための手動の取得およびチェックです。

リレーションの一貫性を維持するために必要な Add メソッドと Remove メソッドについて話しているのでしょうか。これは無地のOOデザインです。NHibernate を使用していない場合は、まったく同じように記述する必要があります (同じクラス モデルが与えられた場合)。

関数からユーザーを削除し、ユーザーにカスケードするなど...

いいえ。オブジェクトが削除されると、カスケード削除が発生します。ユーザーを削除するときは、user_has_function をカスケードする必要があります。そこから、関数をカスケードする場合とカスケードしない場合があります。反対方向も同様。「cascade-all-delete-orphans」という概念もあります。これは、通常のカスケードに加えて、オブジェクトがコレクションから削除されると自動的に削除されることを意味します。これはカスケードではありません。これは一種の非常に基本的なガベージ コレクションです。あなたのケースでこれを利用したい場合は、オブジェクトを 2 回削除しようとするため、user->user_has_function コレクションと function->user_has_function コレクションの両方に適用しないでください。

両方のコレクションを逆にマップすることを忘れないでください。そうしないと、エントリが重複する可能性があります。

3 つのマッピング (user->user_has_function コレクション、function->user_has_function、および user_has_function クラス マッピング) が同じテーブル名と外部キー名を使用していることを確認してください。

複合キーをいじる必要はありません。

于 2012-05-30T11:07:21.730 に答える
0

IList にリレーションを含める代わりに、ISet を使用することになりました。ISet は重複を許可しませんが、IList は許可します。ISet を使用するには、ISet に格納されているオブジェクトの Equals メソッドと GetHashCode メソッドをオーバーライドする必要があります。

XUser と XFunction からカスケードしますが、その逆ではなく、カスケードのために 1 つのエンティティを削除すると、3 つのテーブルすべてのすべてのレコードが削除されました。

これが私がそれを解決した方法です。

エンティティ:

public class XUser
{
    public virtual int Id { get; set; }
    ...
    public virtual ISet<XUserHasXFunction> XUserHasXFunctions { get; set; }

    public XUser()
    {
        XUserHasXFunctions = new HashedSet<XUserHasXFunction>();
    }

    public virtual void AddXFunction(XFunction xFunction, int isActive)
    {
        var xUserHasXFunction = new XUserHasXFunction()
                                    {
                                        XUser = this,
                                        XFunction = xFunction,
                                        IsActive = isActive,
                                        DeployedDate = DateTime.Now
                                    };
        if (XUserHasXFunctions.Contains(xUserHasXFunction) && xFunction.XUserHasXFunctions.Contains(xUserHasXFunction))
        {
            return;
        }
        XUserHasXFunctions.Add(xUserHasXFunction);
        xFunction.XUserHasXFunctions.Add(xUserHasXFunction);
    }

    public virtual void RemoveXFunction(XFunction xFunction)
    {
        var xUserHasXFunction = XUserHasXFunctions.Single(x => x.XFunction == xFunction);
        XUserHasXFunctions.Remove(xUserHasXFunction);
        xFunction.XUserHasXFunctions.Remove(xUserHasXFunction);
    }
}

public class XFunction
{
    public virtual int Id { get; set; }
    ...
    public virtual ISet<XUserHasXFunction> XUserHasXFunctions { get; set; }

    public XFunction()
    {
        XUserHasXFunctions = new HashedSet<XUserHasXFunction>();
    }

    public virtual void AddXUser(XUser xUser, int isActive)
    {
        var xUserHasXFunction = new XUserHasXFunction()
                                    {
                                        XUser = xUser,
                                        XFunction = this,
                                        IsActive = isActive,
                                        DeployedDate = DateTime.Now
                                    };
        if (XUserHasXFunctions.Contains(xUserHasXFunction) && xUser.XUserHasXFunctions.Contains(xUserHasXFunction))
        {
            return;
        }
        XUserHasXFunctions.Add(xUserHasXFunction);
        xUser.XUserHasXFunctions.Add(xUserHasXFunction);
    }

    public virtual void RemoveXUser(XUser xUser)
    {
        var xUserHasXFunction = XUserHasXFunctions.Single(x => x.XUser == xUser);
        XUserHasXFunctions.Remove(xUserHasXFunction);
        xUser.XUserHasXFunctions.Remove(xUserHasXFunction);
    }
}

public class XUserHasXFunction
{
    public virtual int Id { get; set; }
    ...
    public virtual DateTime DeployedDate { get; set; }

    public override bool Equals(object obj)
    {
        if (obj == null)
            return false;
        var t = obj as XUserHasXFunction;
        if (t == null)
            return false;
        return XUser == t.XUser && XFunction == t.XFunction;
    }

    public override int GetHashCode()
    {
        return (XUser.Id + "|" + XFunction.Id).GetHashCode();
    }
}

マッピング:

public class XUserMap : ClassMap<XUser>
{
    public XUserMap()
    {
        Id(x => x.Id, "ID").GeneratedBy.Sequence("SEQ").Column("ID");
        Table("XUSER");
        ...
        HasMany(x => x.XUserHasXFunctions).KeyColumn("XUSER_ID").Cascade.All();
    }
}

public class XFunctionMap : ClassMap<XFunction>
{
    public XFunctionMap()
    {
        Id(x => x.Id, "ID").GeneratedBy.Sequence("SEQ").Column("ID");
        Table("XFUNCTION");
        ...
        HasMany(x => x.XUserHasXFunctions)KeyColumn("XFUNCTION_ID").Cascade.All();
    }
}

public class XUserHasXFunctionMap : ClassMap<XUserHasXFunction>
{
    public XUserHasXFunctionMap()
    {
        Id(x => x.Id, "ID").GeneratedBy.Sequence("SEQ").Column("ID");
        Table("XUSER_HAS_XFUNCTION");
        ...
        Map(x => x.DeployedDate, "DEPLOYED_DATE");

        References(x => x.XUser).Column("XUSER_ID");
        References(x => x.XFunction).Column("XFUNCTION_ID");
    }
}

使用法:

To add relations.
xFunction.AddXUser(xUser, isActive); //visa versa if you like to add a function to a user...
dao.Store(xFunction); //to actually add the relation in the db

now to remove relation
xFunction.RemoveXUser(xUser); //Realtion is removed but neither of the objects xFunction or xUser
dao.Store(xFunction); //...same

to remove a user and its relations.
dao.delete(xUser); //but the xFunction object it was connected to is not removed
//if you want the xFunction object to be removed you have to do that manually.
于 2012-05-31T11:27:12.833 に答える
0

私は少し前にuser、group、user_groupで同様のことをしてしまい、両方のオブジェクトが両側に存在し、手動で保存または更新を選択するというハッキーな方法を使用する必要がありました。

私はあなたが望むことを行うためのNICEの方法はないと思います。データベースの観点からはかなり論理的ですが、モデリングの観点からは面倒なことであることに同意します。

また、user_has_function テーブルに複合キーを使用して、複数のユーザーに対して複数の機能を使用できるようにする必要があると思います。ほとんどの人はこれを避けようとし、代理キーまたはその他のアプローチを使用することになると思います。

これが答えではないことはわかっていますが、投稿したときに同じ質問に対する本当の答えは見つかりませんでした。

これは、私がしばらく前に投稿した同様の質問です。

Nibernate複合キーの質問

于 2012-05-30T10:40:26.200 に答える