我有两个类,用户和角色,定义为:
public class User : Entity
{
// other properties ...
public virtual string Username
public virtual ICollection<Role> Roles { get; set; }
}
public class Role : Entity
{
public virtual string Name { get; set; }
public virtual ICollection<User> Users { get; set; }
}
在我的映射代码中,我有以下内容:
mapper.Class<User>(map =>
{
map.Bag(x=>x.Roles,
cm=>
{
cm.Table("UserRole");
cm.Cascade(Cascade.All);
cm.Key(k => k.Column("[User]"));
},
em=>
{
em.ManyToMany(mm =>
{
mm.Column("[Role]");
});
});
});
mapper.Class<Role>(map =>
{
map.Bag(x=>x.Users,
cm=>
{
cm.Inverse(true);
cm.Table("UserRole");
cm.Key(k=>k.Column("[Role]"));
},
em =>
{
em.ManyToMany(mm =>
{
mm.Column("[User]");
});
});
});
映射生成预期的架构,但从不填充连接表。在其集合中添加具有新角色的新用户会将角色和用户持久保存到相应的表中,但是连接表将保留为空。为什么呢?
编辑:我还没有取得任何进展。我绝对确定映射是正确的,并且生成了正确的模式,但是没有填充连接表。出于测试目的,我正在使用NBuilder生成实体,如下所示:
var roles = new Role[]
{
new Role("Admin"),
new Role("Manager"),
new Role("User")
};
var users = Builder<User>.CreateListOfSize(10)
.TheFirst(1)
.Do(x =>
{
x.Roles.Add(roles[0]);
x.Roles.Add(roles[1]);
roles[0].Users.Add(x);
roles[1].Users.Add(x);
})
.All()
.With(x => x.Id = 0)
.And(x => x.Version = 0)
.And(x => x.Username = "test user")
.And(x => x.Password = "test password")
.Do(x =>
{
x.Roles.Add(roles[2]);
roles[2].Users.Add(x);
}
.Build();
foreach (var u in users) session.Save(u);
用户和角色实体已正确保留,但连接表仍为空。这意味着我无法在以后有效地查询给定用户的角色,这会使该点无效。
答案 0 :(得分:1)
确保您有两个类互相引用。
我认为代码与下面的代码类似,应该对您有用:
role.Users.Add(user);
user.Roles.Add(role);
session.Save(user); // NH only saves user and role, so it can get auto-generated identity fields
session.Flush(); // NH now can save into cross-ref table, because it knows required information (Flush is also called inside of Transaction.Commit())
我找到了一个关于多对多问题的good answer,有很多解释和来自NH文档的引用。我认为值得一读。
[编辑]
在回答this somewhat similar问题时,讨论了需要将显式事务保存到交叉表中的问题。
我还编辑了上面的代码,添加session.Flush()
以反映我的发现。
答案 1 :(得分:0)
我最终下载了NHibernate源并直接引用它,所以我可以逐步完成它。事实证明,它与我生成测试数据的代码没有包装在显式会话事务中这一事实有关。一旦我补充说,这很好。我很想看到这方面的某种解释,因为我无法非常清楚地遵循这些代码,但我至少对这个问题的解决感到满意。