NHibernate从入门到精通系列(10)——多对多关联映射

长平狐 发布于 2012/06/11 11:54
阅读 402
收藏 1

 

内容摘要

单向多对多关联映射

双向多对多关联映射

 

一、单向多对多关联映射

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  

 

代码下载

出处:http://www.cnblogs.com/GoodHelper/archive/2011/03/04/nhibernate10.html

欢迎转载,但需保留版权。


原文链接:http://www.cnblogs.com/GoodHelper/archive/2011/03/04/nhibernate10.html
加载中
返回顶部
顶部