NHibernate从入门到精通系列(10)——多对多关联映射
来源:互联网 发布:ios开发中数据库 编辑:程序博客网 时间:2024/06/05 23:01
内容摘要
单向多对多关联映射
双向多对多关联映射
一、单向多对多关联映射
1.1 多对多关联映射描述
众所周知,持久化类的有三种对应关系:“一对一”、“一对多(多对一)”和“多对多”。在项目开发过程中,我们接触过权限系统。而权限系统中,“用户”和“角色”的对应关系往往就是“多对多”。
让我们看一下“多对多”的数据,如图1.1.1所示:
图1.1.1
从数据中,我们能够观察到:多个用户(User)对应多个角色(Role)。构造“多对多”的关联关系,我们不仅需要用户(User)表和角色(Role)表,还需要用户和角色的关系表。通过这三张表的关系构造了“多对多”的关联关系。
让我们看一下代码:
public class Role { public virtual int? ID { get; set; } public virtual string Name { get; set; } } public class User { public virtual int? ID { get; set; } public virtual string Name { get; set; } public virtual IList<Role> Roles { get; set; } }
映射文件:
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Domain" namespace="Domain"> <class name="Role" table="T_Role" lazy="true" > <id name="ID" type="int" column="RoleID"> <generator class="native"/> </id> <property name="Name" type="string"> <column name="Name" length="50"/> </property> </class></hibernate-mapping><hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Domain" namespace="Domain"> <class name="User" table="T_User" lazy="true" > <id name="ID" type="int" column="UserID"> <generator class="native"/> </id> <property name="Name" type="string"> <column name="Name" length="50"/> </property> <bag name="Roles" table="T_User_Role"> <key column="UserID"/> <many-to-many class="Role" column="RoleID"/> </bag> </class></hibernate-mapping>
在用户(User)类中有与角色(Role)对应的IList<Role>属性Roles,在映射文件中我们用<bag>和<many-to-many>标签描述“多对多”关联映射。
其中,<bag>标签中的“table”属性是设置“多对多”映射的第三方的关系表。注意的是“T_User_Role”这个第三方关系表不在持久化类的结构中体现。<key>标签的“column”属性用于指定主键表的主键,<many-to-many>标签的“column”属性用于指定外键表的关联字段。
1.2 单向多对多关联映射的数据插入
我们编写单元测试类的代码:
[TestFixture] public class ManyToManyTest { private ISessionFactory sessionFactory; public ManyToManyTest() { log4net.Config.XmlConfigurator.Configure(); } [SetUp] public void Init() { var cfg = new NHibernate.Cfg.Configuration().Configure("Config/hibernate.cfg.xml"); sessionFactory = cfg.BuildSessionFactory(); } [Test] public void SaveTest() { using (ISession session = this.sessionFactory.OpenSession()) { var role1 = new Role { Name = "库管" }; var role2 = new Role { Name = "出纳" }; var role3 = new Role { Name = "会计" }; var liu = new User { Name = "刘冬", Roles = new List<Role> { role1, role2 } }; var zhang = new User { Name = "张三" , Roles = new List<Role> { role2, role3 } }; ITransaction tran = session.BeginTransaction(); try { session.Save(role1); session.Save(role2); session.Save(role3); session.Save(liu); session.Save(zhang); tran.Commit(); } catch(Exception ex) { tran.Rollback(); throw ex; } } }}
运行效果如图1.2.1所示,运行成功。
图1.2.1
首先生成了主表的“insert into”语句,其次生成关系表的“insert into”语句。
二、双向多对多关联映射
2.1 双向多对多关联映射的描述
实现双向多对多关联映射需要修改一下代码和映射文件:
public class Role { public virtual int? ID { get; set; } public virtual string Name { get; set; } public virtual IList<User> Users { get; set; } }
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Domain" namespace="Domain"> <class name="Role" table="T_Role" lazy="true" > <id name="ID" type="int" column="RoleID"> <generator class="native"/> </id> <property name="Name" type="string"> <column name="Name" length="50"/> </property> <bag name="Users" table="T_User_Role"> <key column="RoleID"/> <many-to-many class="User" column="UserID"/> </bag> </class></hibernate-mapping>
在角色(Role)类中建立用户(User)的IList<User>属性“Users”。这样,多个角色(Role)对应多个用户(User),多个用户(User)也对应多个角色(Role)。
2.2 双向多对多关联映射的数据插入
编写单元测试代码:
[Test] public void SaveRoleTest() { using (ISession session = this.sessionFactory.OpenSession()) { var user = new User { Name = "刘冬" }; var role = new Role { Name = "系统管理员", Users = new List<User> { user } }; ITransaction tran = session.BeginTransaction(); try { session.Save(user); session.Save(role); tran.Commit(); } catch (Exception ex) { tran.Rollback(); throw ex; } } }
运行效果如图2.2.1所示,运行成功
图2.2.1
设置cascade属性为all,用于从一端保存数据。
<bag name="Roles" table="T_User_Role" cascade="all"> <key column="UserID"/> <many-to-many class="Role" column="RoleID"/> </bag>
[Test] public void SaveUserTest() { using (ISession session = this.sessionFactory.OpenSession()) { var role = new Role { Name = "系统管理员", }; var user = new User { Name = "刘冬", Roles = new List<Role> { role } }; ITransaction tran = session.BeginTransaction(); try { session.Save(user); tran.Commit(); } catch (Exception ex) { tran.Rollback(); throw ex; } } }
运行效果如图2.2.2所示,运行成功。
图2.2.2
我们设置<bag>标签的inverse为true:
<bag name="Roles" table="T_User_Role" inverse="true" cascade="all"> <key column="UserID"/> <many-to-many class="Role" column="RoleID"/> </bag>
运行效果如图2.2.3所示,虽然运行成功,但没有将数据插入关系表“T_User_Role”。
图2.2.3
这是为什么呢?因为“inverse”属性的意思是反转,就是将操作权交给关联关系的另一点,“多对多”关联映射的另一端始终是它们的“关系表”。正因为“关系表”不在持久化类中体现,所以在“多对多”关联映射中设置“inverse”属性是没有意义的。
2.3 双向多对多关联映射的数据更新
我们编写单元测试的代码:
[Test] public void UpdateUserTest() { using (ISession session = this.sessionFactory.OpenSession()) { var role = new Role { Name = "系统管理员", }; var user = session.Get<User>(1); user.Roles.Clear(); user.Roles.Add(role); ITransaction tran = session.BeginTransaction(); try { session.Update(user); tran.Commit(); } catch (Exception ex) { tran.Rollback(); throw ex; } } }
运行效果如图2.3.1所示,运行成功。生成了“delete”语句,删除了原有集合的数据,然后插入了新的集合数据。
图2.3.1
2.4 双向多对多关联映射的数据查询
编写单元测试类代码:
[Test] public void SelectTest() { using (ISession session = this.sessionFactory.OpenSession()) { var user = session.Get<User>(1); foreach (var item in user.Roles) { Console.WriteLine("角色名称:{0}", item.Name); foreach (var us in item.Users) { Console.WriteLine("用户名称:{0}", us.Name); } } } }
运行效果如图2.4.1所示,运行成功。
图2.4.1
- NHibernate从入门到精通系列(10)——多对多关联映射
- NHibernate从入门到精通系列(7)——多对一关联映射
- NHibernate多对多单双向关联映射-NHibernate入门到精通系列10
- NHibernate从入门到精通系列(9)——一对多关联映射
- NHibernate从入门到精通系列(8)——一对一关联映射
- NHibernate一对多单双向关联映射-NHibernate入门到精通系列9
- NHibernate多对一xml映射-NHibernate入门到精通系列7
- NHibernate从入门到精通系列(6)——基本映射
- NHibernate从入门到精通系列(6)——基本映射
- 【Hibernate】从入门到精通(七)关联映射之多对多映射
- Hibernate从入门到精通(十)多对多单向关联映射
- Hibernate从入门到精通(十一)多对多双向关联映射
- Hibernate从入门到精通(十)多对多单向关联映射
- Hibernate从入门到精通(十一)多对多双向关联映射
- Hibernate从入门到精通(七)多对一单向关联映射
- Hibernate从入门到精通(七)多对一单向关联映射 .
- Hibernate从入门到精通(七)多对一单向关联映射
- NHibernate从入门到精通系列(1)——NHibernate概括
- 判断一个字符是否是另一个字符的旋转字符串
- C++读取windows系统性能技术器(PDH)
- java+android须知环境变量配置
- 关于自己学习ios oc的学习笔记
- 如何快速使用PPPOE服务器?
- NHibernate从入门到精通系列(10)——多对多关联映射
- iphone程序中实现截屏的一种方法
- ORA-12520听程序无法为请求的服务器类型找到可用的处理程序
- Android 多分辨率自适应总结
- 一个很详细的web.xml讲解
- 欢迎使用CSDN-markdown编辑器
- Can't connect to local MYSQL server through socket /var/lib/mysql/mysql.sock
- js+flash实现,单击按钮复制文本框内容
- linux下查看已经安装的jdk 并卸载jdk