NHibernate关联讲解
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Many-To-Many 双向关联
1.双向N——N关联的两边都需要指定连接表的表名,外键列的列名。
2.两个set元素table必须指定,并且必须相同。
3.set元素的两个字元素:key和many-to-many都必须指定column属性,key和many-to-many分别制定本持久化类,关联类在连接表中的外键列名,因此两边的key与many-to-many的column属性交叉相同。
例如:
T_User表 T_User_Role T_Role表
Id Int主键自增 UserId User表id Id Int主键自增
UserName String 50 RoleId Role表id RoleName String 50
UserPassword String 50
User类:
―――――――――――――――――――――――――
using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
namespace NHibernateTest.Model
{
[Serializable]
public class User
{
private int _userid;
public virtual int UserId
{
get { return _userid; }
set { _userid = value; }
}
private string _username;
public virtual string UserName
{
get { return _username; }
set { _username = value; }
}
private string _userpassword;
public virtual string UserPassword
{
get { return _userpassword; }
set { _userpassword = value; }
}
private IList _roles;
public virtual IList Roles
{
get { return _roles; }
set { _roles = value; }
}
public User()
{
_userid = 0;
_username = null;
_userpassword = null;
_roles = new ArrayList();
}
}
}
Role类:
―――――――――――――――――――――――
using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
namespace NHibernateTest.Model
{
[Serializable]
public class Role
{
private int _roleid;
public virtual int RoleId
{
get { return _roleid; }
set { _roleid = value; }
}
private string _rolename;
public virtual string RoleName
{
get { return _rolename; }
set { _rolename = value; }
}
private IList _users;
public virtual IList Users
{
get { return _users; }
set { _users = value; }
}
public Role()
{
_roleid = 0;
_rolename =null;
_users = new ArrayList();
}
}
}
User类映射文件User.hbm.xml:
-----------------------------------------------------------------------------
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class name="NHibernateTest.Model.User,NHibernateTest.Model"
table="T_User">
<id name="UserId" column="Id" type="Int32" unsaved-value="0">
<generator class="native"/>
</id>
<property column="UserName" type="String" name="UserName" not-null="true" length="50" />
<property column="UserPassword" type="String" name="UserPassword" not-null="true" length="50" />
<bag name="Roles" table="T_User_Role" lazy="true">
<!--指定本持久化类(User)在连接表(T_User_Role)中的外键列名UserId,也就是T_User_Role表的UserId -->
<key column="UserId"/>
<!--指定关联类(Role)在连接表(T_User_Role)中的外键列名RoleId -->
<many-to-many class="NHibernateTest.Model.Role,NHibernateTest.Model" column="RoleId"/>
</bag>
</class>
</hibernate-mapping>
Role类映射文件 Role.hbm.xml:
---------------------------------------------------
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class name="NHibernateTest.Model.Role,NHibernateTest.Model" table="T_Role">
<id name="RoleId" column="Id" type="Int32" unsaved-value="0">
<generator class="native"/>
</id>
<property column="RoleName" type="String" name="RoleName" not-null="true" length="50" />
<bag name="Users" table="T_User_Role" lazy="true" inverse="true">
<!--指定本持久化类(Role)在连接表(T_User_Role)中的外键列名,也就是T_User_Role表的RoleId-->
<key column="RoleId"/>
<!--指定关联类(User)在连接表(T_User_Role)中的外键列名-->
<many-to-many class="NHibernateTest.Model.User,NHibernateTest.Model" column="UserId"/>
</bag>
</class>
</hibernate-mapping>
实现代码如下:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using NHibernateTest.Model;
using NHibernate;
using NHibernate.Cfg;
using NHibernate.Tool.hbm2ddl;
namespace NHibernateTest
{
/* many-to-many和别的关联映射有所不同。
* 例子中:Role和User没有直接的依赖关系,而是通过一张中间表完成。
* 在删除User时一般不会要求删除Role,而是删除之间的关系
* (即从中间表删除数据)。
*/
public partial class Many_To_Many : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void TestAddRoleToUser_Click(object sender, EventArgs e)
{
Configuration config = new Configuration();
config.AddAssembly("NHibernateTest.Model");
ISessionFactory sessions = config.BuildSessionFactory();
ISession session = sessions.OpenSession();
ITransaction trans = session.BeginTransaction();
try
{
User user = session.Load(typeof(User), 4) as User;
Role role = session.Load(typeof(Role), 4) as Role;
user.Roles.Add(role);
role.Users.Add(user);
session.Update(user);
trans.Commit();
}
catch
{
trans.Rollback();
throw new Exception("失败!");
}
finally
{
session.Close();
}
}
//移除user和role的关联关系
protected void TestRemoveRoleFromUser_Click(object sender, EventArgs e)
{
Configuration config = new Configuration();
config.AddAssembly("NHibernateTest.Model");
ISessionFactory sessions = config.BuildSessionFactory();
ISession session = sessions.OpenSession();
ITransaction trans = session.BeginTransaction();
try
{
//移除user和role的关联关系
User user = session.Load(typeof(User), 5) as User;
Role role = session.Load(typeof(Role), 5) as Role;
user.Roles.Remove(role);
role.Users.Remove(user);
session.Update(user);
trans.Commit();
}
catch
{
trans.Rollback();
throw new Exception("失败!");
}
finally
{
session.Close();
}
}
//更新了与UserId=6关联的Role的RoleName名字
protected void TestUpdateUserWithRole_Click(object sender, EventArgs e)
{
Configuration config = new Configuration();
config.AddAssembly("NHibernateTest.Model");
ISessionFactory sessions = config.BuildSessionFactory();
ISession session = sessions.OpenSession();
ITransaction trans = session.BeginTransaction();
try
{
//更新了与UserId=6关联的Role的RoleName名字
User user = session.Load(typeof(User), 6) as User;
((Role)user.Roles[0]).RoleName = "UpdateRole";
session.Update(user);
trans.Commit();
}
catch
{
trans.Rollback();
throw new Exception("失败!");
}
finally
{
session.Close();
}
}
//删除T_User表id=10的记录和删除了T_User_Role表的UserId=10的记录
//跟踪Sql:go
/* DELETE FROM T_User_Role WHERE UserId = @p0', N'@p0 int', @p0 = 10
DELETE FROM T_User WHERE Id = @p0', N'@p0 int', @p0 = 10
*/
protected void TestDeleteUserWithSetRole_Click(object sender, EventArgs e)
{
Configuration config = new Configuration();
config.AddAssembly("NHibernateTest.Model");
ISessionFactory sessions = config.BuildSessionFactory();
ISession session = sessions.OpenSession();
ITransaction trans = session.BeginTransaction();
try
{
User user = session.Load(typeof(User), 10) as User;
session.Delete(user);
trans.Commit();
}
catch
{
trans.Rollback();
throw new Exception("失败!");
}
finally
{
session.Close();
}
}
//添加了User,Role 以及User-Role的关系
protected void TestAddUserAndRole_Click(object sender, EventArgs e)
{
Configuration config = new Configuration();
config.AddAssembly("NHibernateTest.Model");
ISessionFactory sessions = config.BuildSessionFactory();
ISession session = sessions.OpenSession();
ITransaction trans = session.BeginTransaction();
try
{
User user = new User();
user.UserName = "222";
user.UserPassword = "222";
Role role = new Role();
role.RoleName = "秘书";
role.Users.Add(user);
user.Roles.Add(role);
session.Save(user);
session.Save(role);
trans.Commit();
}
catch
{
trans.Rollback();
throw new Exception("失败!");
}
finally
{
session.Close();
}
}
}
}
One-To-Many(单项关联1-N)
因为集合属性都需要保存到另一个数据表中,所以保存集合属性表必须必须包含一个外键列,用于参照主键列。该外键列通过在<Set/>等集合元素中使用<key…/>子元素column来映射。不管使用那种集合,使用<bag../>元素都将映射成无序集合。集合属性对应的表没有主键。
对于1—N的单向关联,需要在1的一端增加对应的集合映射元素。与映射集合类似,必须为<set> ,<bag>等集合元素增加key子元素,用以映射关联外键列。
one-to-many标签包含在标签bag/set中.bag标签的。inverse属性使collection不更新连接。
key标签的column属性指出了在另一个数据库表中加入外键,来关联本类。
T_Parent T_Child
Id Int主键自增 ChildId Int自增
Name String Name String
ParentId T_Parent表Id
Many-To-One
many-to-one:描述多对一的一种数据模型,它指定many一方是不能独立存在的,我个人认为many-to-one是NHB中保证数据有效性的最有用的一种映射,通过使用many-to-one能有效的防治孤儿记录被写入到数据表中。
<many-to-one
name="propertyName"(1)
column="column_name"(2)
class="ClassName"(3)
cascade="all|none|save-update|delete"(4)
unique="true|false" (10)
/>
1.name:属性名。指出many一方的类用哪个属性和one一方的类关联.
2.column:字段名(可选).指出many一方的类对应的数据表用哪个列和one一方的类对应的数据表关联(两表之间存在外键关联);
3.class:关联的类的名字(可选 - 默认是通过反射得到属性类型);
4.cascade:指明哪些操作会从父对象级联到关联的对象(可选).cascade属性允许下列值:: all, save-update, delete, none. 设置除了none以外的其它值会传播特定的操作到关联的(子)对象中。
5.unique:允许产生外键列唯一约束的数据库定义语言(DDL)(可选)
1.双向N——N关联的两边都需要指定连接表的表名,外键列的列名。
2.两个set元素table必须指定,并且必须相同。
3.set元素的两个字元素:key和many-to-many都必须指定column属性,key和many-to-many分别制定本持久化类,关联类在连接表中的外键列名,因此两边的key与many-to-many的column属性交叉相同。
例如:
T_User表 T_User_Role T_Role表
Id Int主键自增 UserId User表id Id Int主键自增
UserName String 50 RoleId Role表id RoleName String 50
UserPassword String 50
User类:
―――――――――――――――――――――――――
using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
namespace NHibernateTest.Model
{
[Serializable]
public class User
{
private int _userid;
public virtual int UserId
{
get { return _userid; }
set { _userid = value; }
}
private string _username;
public virtual string UserName
{
get { return _username; }
set { _username = value; }
}
private string _userpassword;
public virtual string UserPassword
{
get { return _userpassword; }
set { _userpassword = value; }
}
private IList _roles;
public virtual IList Roles
{
get { return _roles; }
set { _roles = value; }
}
public User()
{
_userid = 0;
_username = null;
_userpassword = null;
_roles = new ArrayList();
}
}
}
Role类:
―――――――――――――――――――――――
using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
namespace NHibernateTest.Model
{
[Serializable]
public class Role
{
private int _roleid;
public virtual int RoleId
{
get { return _roleid; }
set { _roleid = value; }
}
private string _rolename;
public virtual string RoleName
{
get { return _rolename; }
set { _rolename = value; }
}
private IList _users;
public virtual IList Users
{
get { return _users; }
set { _users = value; }
}
public Role()
{
_roleid = 0;
_rolename =null;
_users = new ArrayList();
}
}
}
User类映射文件User.hbm.xml:
-----------------------------------------------------------------------------
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class name="NHibernateTest.Model.User,NHibernateTest.Model"
table="T_User">
<id name="UserId" column="Id" type="Int32" unsaved-value="0">
<generator class="native"/>
</id>
<property column="UserName" type="String" name="UserName" not-null="true" length="50" />
<property column="UserPassword" type="String" name="UserPassword" not-null="true" length="50" />
<bag name="Roles" table="T_User_Role" lazy="true">
<!--指定本持久化类(User)在连接表(T_User_Role)中的外键列名UserId,也就是T_User_Role表的UserId -->
<key column="UserId"/>
<!--指定关联类(Role)在连接表(T_User_Role)中的外键列名RoleId -->
<many-to-many class="NHibernateTest.Model.Role,NHibernateTest.Model" column="RoleId"/>
</bag>
</class>
</hibernate-mapping>
Role类映射文件 Role.hbm.xml:
---------------------------------------------------
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class name="NHibernateTest.Model.Role,NHibernateTest.Model" table="T_Role">
<id name="RoleId" column="Id" type="Int32" unsaved-value="0">
<generator class="native"/>
</id>
<property column="RoleName" type="String" name="RoleName" not-null="true" length="50" />
<bag name="Users" table="T_User_Role" lazy="true" inverse="true">
<!--指定本持久化类(Role)在连接表(T_User_Role)中的外键列名,也就是T_User_Role表的RoleId-->
<key column="RoleId"/>
<!--指定关联类(User)在连接表(T_User_Role)中的外键列名-->
<many-to-many class="NHibernateTest.Model.User,NHibernateTest.Model" column="UserId"/>
</bag>
</class>
</hibernate-mapping>
实现代码如下:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using NHibernateTest.Model;
using NHibernate;
using NHibernate.Cfg;
using NHibernate.Tool.hbm2ddl;
namespace NHibernateTest
{
/* many-to-many和别的关联映射有所不同。
* 例子中:Role和User没有直接的依赖关系,而是通过一张中间表完成。
* 在删除User时一般不会要求删除Role,而是删除之间的关系
* (即从中间表删除数据)。
*/
public partial class Many_To_Many : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void TestAddRoleToUser_Click(object sender, EventArgs e)
{
Configuration config = new Configuration();
config.AddAssembly("NHibernateTest.Model");
ISessionFactory sessions = config.BuildSessionFactory();
ISession session = sessions.OpenSession();
ITransaction trans = session.BeginTransaction();
try
{
User user = session.Load(typeof(User), 4) as User;
Role role = session.Load(typeof(Role), 4) as Role;
user.Roles.Add(role);
role.Users.Add(user);
session.Update(user);
trans.Commit();
}
catch
{
trans.Rollback();
throw new Exception("失败!");
}
finally
{
session.Close();
}
}
//移除user和role的关联关系
protected void TestRemoveRoleFromUser_Click(object sender, EventArgs e)
{
Configuration config = new Configuration();
config.AddAssembly("NHibernateTest.Model");
ISessionFactory sessions = config.BuildSessionFactory();
ISession session = sessions.OpenSession();
ITransaction trans = session.BeginTransaction();
try
{
//移除user和role的关联关系
User user = session.Load(typeof(User), 5) as User;
Role role = session.Load(typeof(Role), 5) as Role;
user.Roles.Remove(role);
role.Users.Remove(user);
session.Update(user);
trans.Commit();
}
catch
{
trans.Rollback();
throw new Exception("失败!");
}
finally
{
session.Close();
}
}
//更新了与UserId=6关联的Role的RoleName名字
protected void TestUpdateUserWithRole_Click(object sender, EventArgs e)
{
Configuration config = new Configuration();
config.AddAssembly("NHibernateTest.Model");
ISessionFactory sessions = config.BuildSessionFactory();
ISession session = sessions.OpenSession();
ITransaction trans = session.BeginTransaction();
try
{
//更新了与UserId=6关联的Role的RoleName名字
User user = session.Load(typeof(User), 6) as User;
((Role)user.Roles[0]).RoleName = "UpdateRole";
session.Update(user);
trans.Commit();
}
catch
{
trans.Rollback();
throw new Exception("失败!");
}
finally
{
session.Close();
}
}
//删除T_User表id=10的记录和删除了T_User_Role表的UserId=10的记录
//跟踪Sql:go
/* DELETE FROM T_User_Role WHERE UserId = @p0', N'@p0 int', @p0 = 10
DELETE FROM T_User WHERE Id = @p0', N'@p0 int', @p0 = 10
*/
protected void TestDeleteUserWithSetRole_Click(object sender, EventArgs e)
{
Configuration config = new Configuration();
config.AddAssembly("NHibernateTest.Model");
ISessionFactory sessions = config.BuildSessionFactory();
ISession session = sessions.OpenSession();
ITransaction trans = session.BeginTransaction();
try
{
User user = session.Load(typeof(User), 10) as User;
session.Delete(user);
trans.Commit();
}
catch
{
trans.Rollback();
throw new Exception("失败!");
}
finally
{
session.Close();
}
}
//添加了User,Role 以及User-Role的关系
protected void TestAddUserAndRole_Click(object sender, EventArgs e)
{
Configuration config = new Configuration();
config.AddAssembly("NHibernateTest.Model");
ISessionFactory sessions = config.BuildSessionFactory();
ISession session = sessions.OpenSession();
ITransaction trans = session.BeginTransaction();
try
{
User user = new User();
user.UserName = "222";
user.UserPassword = "222";
Role role = new Role();
role.RoleName = "秘书";
role.Users.Add(user);
user.Roles.Add(role);
session.Save(user);
session.Save(role);
trans.Commit();
}
catch
{
trans.Rollback();
throw new Exception("失败!");
}
finally
{
session.Close();
}
}
}
}
One-To-Many(单项关联1-N)
因为集合属性都需要保存到另一个数据表中,所以保存集合属性表必须必须包含一个外键列,用于参照主键列。该外键列通过在<Set/>等集合元素中使用<key…/>子元素column来映射。不管使用那种集合,使用<bag../>元素都将映射成无序集合。集合属性对应的表没有主键。
对于1—N的单向关联,需要在1的一端增加对应的集合映射元素。与映射集合类似,必须为<set> ,<bag>等集合元素增加key子元素,用以映射关联外键列。
one-to-many标签包含在标签bag/set中.bag标签的。inverse属性使collection不更新连接。
key标签的column属性指出了在另一个数据库表中加入外键,来关联本类。
T_Parent T_Child
Id Int主键自增 ChildId Int自增
Name String Name String
ParentId T_Parent表Id
Many-To-One
many-to-one:描述多对一的一种数据模型,它指定many一方是不能独立存在的,我个人认为many-to-one是NHB中保证数据有效性的最有用的一种映射,通过使用many-to-one能有效的防治孤儿记录被写入到数据表中。
<many-to-one
name="propertyName"(1)
column="column_name"(2)
class="ClassName"(3)
cascade="all|none|save-update|delete"(4)
unique="true|false" (10)
/>
1.name:属性名。指出many一方的类用哪个属性和one一方的类关联.
2.column:字段名(可选).指出many一方的类对应的数据表用哪个列和one一方的类对应的数据表关联(两表之间存在外键关联);
3.class:关联的类的名字(可选 - 默认是通过反射得到属性类型);
4.cascade:指明哪些操作会从父对象级联到关联的对象(可选).cascade属性允许下列值:: all, save-update, delete, none. 设置除了none以外的其它值会传播特定的操作到关联的(子)对象中。
5.unique:允许产生外键列唯一约束的数据库定义语言(DDL)(可选)