1

メンバーシップ システムに NHibernate を使用しています。は多くののUserメンバーになることができ、多くのユーザーを持つことができます。RoleRole

aRoleまたは aUserが削除された場合、関連付けレコード (「RoleUsers」テーブル) の削除のみをカスケードする必要があります。

Role期待どおりに作品を削除します。ただし、 を削除しUserても関連付けレコードは削除されないため、外部キー制約により失敗します。

側の私のマッピングRole:

        HasManyToMany(r => r.Users)
            .Access.CamelCaseField()
            .Table("RoleUsers")
            .ParentKeyColumn("RoleId")
            .ChildKeyColumn("UserId")
            .AsSet();

側面のマッピングUser:

        HasManyToMany(u => u.Roles)
            .Access.CamelCaseField()
            .Table("RoleUsers")
            .ParentKeyColumn("UserId")
            .ChildKeyColumn("RoleId")
            .Inverse(); // we'll add user to role, not role to user

そして失敗したテスト:

    [Test]
    public void Deleting_user_should_not_delete_roles()
    {
        var user = new User("john@doe.com", "John", "Doe", "Secr3t");
        var role = new Role("Admin");
        role.AddUser(user);

        object id;
        using (var txn = Session.BeginTransaction())
        {
            id = Session.Save(user);
            Session.Save(role);
            txn.Commit();
        }

        Session.Clear();

        var fromDb = Session.Get<User>(id);

        using (var txn = Session.BeginTransaction())
        {
            Session.Delete(fromDb);
            txn.Commit();
        }

        Session.Query<Role>().Count().ShouldEqual(1);
    }

ユーザーマッピングのすべての組み合わせを試しましCascadeたが、失敗するか、関連レコードとロールを削除します(私が望むものではありません)。

4

1 に答える 1

2

インバースカスケードは 2 つの異なる概念です。そしてもちろん、どちら<many-to-many>リレーションでサポートされています。ドキュメント 6.8 を参照してください (ほぼ 6.9 までスクロールします)。

http://nhibernate.info/doc/nh/en/index.html#collections-bidirectional

1) まず、コレクションの設定を削除できます。User.Rolesこれにより、ロールに対するユーザーの関係の動作が修正され、ユーザー自体が削除される前に強制的に削除されます。

2) 第二に。UserRolesコレクションがとしてマークされている場合、inverse

HasManyToMany(u => u.Roles)
  ...
  .Inverse(); // we'll add user to role, not role to user

Userを削除しても、ペアの削除がトリガーされることはありません。それは、私たちが明示的に言っているからです:関係を気にするのはRole.

したがって、シナリオを続行したい場合:

.逆(); // ロールをユーザーに追加するのではなく、ユーザーをロールに追加します

私たちは一貫している必要があります。「ユーザーからのロールではなく、ロールからユーザーを削除します」:

[Test]
public void Deleting_user_should_not_delete_roles()
{
  var user = new User("john@doe.com", "John", "Doe", "Secr3t");
  var role = new Role("Admin");
  role.AddUser(user);

  object roleId;
  object id;
  using (var txn = Session.BeginTransaction())
  {
    id = Session.Save(user);
    roleId = Session.Save(role);
    txn.Commit();
  }

  Session.Clear();

  // take both from DB
  var userFromDb = Session.Get<User>(id);
  var roleFromDb = Session.Get<Role>(roleId);

  using (var txn = Session.BeginTransaction())
  {
     // HERE just remove the user from collection
     roleFromDb.Users.Remove(userFromDb);

     // all relations will be deleted
     Session.Save(roleFromDb);
     txn.Commit();
  }
  ... 
  // assertions
  // "John's" relation to Role "admin" is deleted
}

注: 3) カスケードはそこでは使用されませんでしたが、Session.Save(user) を減らすのに役立ちます...

編集:ポイントを拡張する3)

Ben Foster がコメントで気づいたユーザーの削除。

3) がそのユーザーコレクションを完全Roleに管理できるようにする必要があります。(casdace="all-delete-orhpan" if User without Role をまったく削除する必要がある場合) を導入しましょう。Role オブジェクトを介してのみユーザーを追加/更新できるようになりました。casdace="all"

Role の Users コレクションのマッピングは次のようになります。

HasManyToMany(r => r.Users)
  .Access.CamelCaseField()
  .Table("RoleUsers")
  .ParentKeyColumn("RoleId")
  .ChildKeyColumn("UserId")
  //.Cascade.All(); // just save or update instance of users
  .Cascade.AllDeleteOrphan(); // will even delete User without any Role
  .AsSet();

逆とカスケードを使用して、テストを調整できます。

[Test]
public void Deleting_user_should_not_delete_roles()
{
  var user = new User("john@doe.com", "John", "Doe", "Secr3t");
  var role = new Role("Admin");
  role.AddUser(user);

  object roleId;
  using (var txn = Session.BeginTransaction())
  {
     // I. no need to save user
     roleId = Session.Save(role);
     ...

そして後でこれを呼び出して、ユーザーを取り除きます

...
using (var txn = Session.BeginTransaction())
{
  var user = Session.Get<User>(id);
  var roles = user.Roles.ToList();
  roles.ForEach(role => role.RemoveUser(user))
  // II. not only relations, but even the User is deleted
  // becuase updated roles triggered delete orhpan
  // (no Session.Update() call there)
  txn.Commit();
}
于 2012-12-07T08:19:48.573 に答える