所谓many2many就是多对多关系,如人员与权限;人员与部门等。
多对多可以将关联表作为一个实体,相关系的表均采用One2Many方法引用这个关联实体。另外一种就是采用真正的Many2Many方式,如下:
在这种情况下,多对多操纵的是三张表,但只有两个实体类。中间的关系表在Nhibernate中是不当作实体来处理的。
示例代码用的是人员与部门。两个类的写法相同,本文以User与Department为例子。
Department.Hbm.xml
< key column ="DEPARTMENT_ID" />
< many-to-many column ="USER_ID" class ="NHibernateStudy.Domain.User, NHibernateStudy.Domain" />
</ bag >
注意:name 属性为在Department类中引用的User数据的名称;
Table属性:为关联表的名称;lazy属性为延迟加载
严重注意:此处不能加入Inverse=true,刚开始加入这个,导致关系表数据插入不进去。仔细思考一下可知,此时关联表对应的无实体类,而将inverse=true实际上是将关系交给many即关联表对应的实体类,而关联表压根没有实体类,所以也就不可能插入。
Key column属性指定当前类在关联表中的列的名称,即关联表与该表连接的外键名称
Many-to-many属性 column:指定,对应的那个类在关联表中的字段,对于Deparment来说就是User类对应的表在关联表中的列。即关联表与User类对应表连接的外键名称。
Cs
public virtual IList < User > Users
{
get { return users; }
set { users = value; }
}
注意: 在变量声明时即生成数组实例。也可以在构造函数中完成此操作。
编译与调用
protected void Button4_Click( object sender, EventArgs e)
{
NHibernateStudy.Domain.User newUser = new NHibernateStudy.Domain.User();
newUser.UserName = "zhyuque";
newUser.Password = "abc1231";
newUser.EmailAddress = "zhyuque@cool.com1";
newUser.LastLogon = DateTime.Now;
Deparment newDep = new Deparment();
newDep.Name = "新员工培训部";
Deparment newDep1 = new Deparment();
newDep1.Name = "人事部";
newUser.Deparments.Add(newDep);
newUser.Deparments.Add(newDep1);
//newDep.Users.Add(newUser); 加入此句话,导致关联表主键重复
//newDep1.Users.Add(newUser); 加入此句话,导致关联表主键重复
string sTmp = "Congratulate, We are succeed!";
ISession session = Sessions.GetSession();
ITransaction trans = session.BeginTransaction();
try
{
session.Save(newDep);
session.Save(newDep1);
session.Save(newUser);
trans.Commit();
}
catch
{
trans.Rollback();
sTmp = "Sorry, Please try again!";
}
finally
{
session.Close();
}
this.TbxHello.Text = sTmp;
}
在调用与编译中一共出现两个问题
1) 关联表数据无法插入,问题解决见上文inverse=true;
2) 插入数据报异常。关键问题就是
newUser.Deparments.Add(newDep1);
// newDep.Users.Add(newUser); 加入此句话,导致关联表主键重复
// newDep1.Users.Add(newUser); 加入此句话,导致关联表主键重复
如果互相加入,会导致主键重复,所以只需要有一方操作关联表即可