我们正在使用NHibernate作为会员系统。 User
可以是许多Role
的成员,而Role
可以包含许多用户。
当删除Role
或User
时,它应该只删除关联记录的删除(“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
的每个组合,它会失败或删除关联记录和角色(不是我想要的)。
答案 0 :(得分:2)
反向和级联是两个不同的概念。当然,<many-to-many>
关系支持 。请参阅文档6.8(向下向下滚动到6.9)
http://nhibernate.info/doc/nh/en/index.html#collections-bidirectional
1)首先,我们可以删除User.Roles
集合的反向设置。这会将用户的关系的行为拉直到角色,并在用户本身被删除之前强行删除。
2)其次。如果用户的角色集合标记为 inverse
,
HasManyToMany(u => u.Roles)
...
.Inverse(); // we'll add user to role, not role to user
删除任何用户,永远不会触发删除该对。那是因为我们明确地说:唯一一个关心这种关系的人是Role
。
因此,如果我们想继续您的方案:
.Inverse(); //我们会将用户添加到角色,而不是将角色添加到用户
我们应该是有益的。 “我们将从角色中移除用户,而不是来自用户的角色”:
[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)那里没有使用Cascade,但可以帮助减少Session.Save(用户)......
删除用户,正如Ben Foster在评论中注意到的那样。
3)我们甚至应该允许Role
完全管理其 Users 集合。让我们介绍casdace="all"
(如果没有任何角色的用户应该删除,则为casdace =“all-delete-orhpan”。现在我们只能通过Role对象添加/更新用户。
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();
}