Nhibernate 1对1映射关系

来源:互联网 发布:windows to go配置 编辑:程序博客网 时间:2024/06/07 04:49

 一对一关联有两种方式:
主键关联(primary key associations)
唯一外键关联(unique foreign key associations)

所谓主键关联是指两者中使用一个主键(使用一个主键?什么意思?这里是说一个表产生主键,别一个表使用一个字段保存对方产生的主键。还不明白?往下的说明就清楚了)。所谓的唯一外键关联是指两表各自有自己的主键,但其中的一个表有一个字段保存了对方的主键。

我们举个例子:数据库有两个表,分别是:Person、Employee。Employee是Person的一个子集(有一部分的person是employee)。

那么我们一般在设置是两表各有一个名为ID的自增字段作为主键,Employee中添加一个Person_ID来关联Person表相关记录。这种关系就是唯一外键关联。我们使用CPerson类对应Person表,CEmployee类对应Employee表,以下是两个类的代码
public class CPerson
    
{        
        
// ID的私有变量
        private int mID;        
        
// Name的私有变量
        private string mName;        
        
// Memo的私有变量
        private string mMemo;        
        
/// <summary>
        
/// 构造函数
        
/// </summary>

        public CPerson()
        {

         }

/// <summary>
 
/// 获取、设置ID
// </summary>

public int ID
        
{
            
get
            
{
                
return this.mID;
            }

            
set
            
{
                
this.mID = value;
            }

        }

        
/**//// <summary>
        
/// 获取、设置Name
        
/// </summary>

        public string Name
        
{
            
get
            
{
                
return this.mName;
            }

            
set
            
{
                
this.mName = value;
            }

        }
        
        
/**//// <summary>
        
/// 获取、设置Memo
        
/// </summary>

        public string Memo
        

            
get
            
{
                
return this.mMemo;
            }

            
set
            
{
                
this.mMemo = value;
            }

        }

    }

public class CEmployee
    
{        
        
// Price的私有变量
        private int mPrice;       
        
// Memo的私有变量
        private string mMemo;        
        
/**//// <summary>
        
/// 构造函数
        
/// </summary>

        public CEmployee()
        
{    
        }

        
        
/**//// <summary>
        
/// 获取、设置Price
        
/// </summary>

        public int Price
        
{
            
get
            
{
                
return this.mPrice;
            }

            
set
            
{
                
this.mPrice = value;
            }

        }

        
private int mID;
        
/**//// <summary>
        
/// 设置、获取ID
        
/// </summary>

        public int ID
        
{
            
get
            
{
                
return this.mID;
            }

            
set
            
{
                
this.mID = value;
            }

        }
  
        
/**//// <summary>
        
/// 获取、设置Memo
        
/// </summary>

        public string Memo
        
{
            
get
            
{
                
return this.mMemo;
            }

            
set
            
{
                
this.mMemo = value;
            }

        }

        
private CPerson mPerson;
        
/**//// <summary>
        
/// 设置、获取Person
        
/// </summary>

        public CPerson Person
        
{
            
get
            
{
                
return this.mPerson;
            }

            
set
            
{
                
this.mPerson = value;
            }

        }
       
    }


CPerson中并没有关于CEmployee的属性,这与我们的数据表很类似。再看一下唯一外键关联使用的映射文件
person.hbm.xml

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0">
 
<class name="EnPrint.DB.CPerson,EnPrint.DB" table="Person">
    
<id name="ID" column="ID" type="Int32">
        
<generator class="identity" />
    
</id>
    
<property name="Name" column="[Name]" type="string" length="50" />
    
<property name="Memo" column="[Memo]" type="string" length="50" />    
  
</class>
</hibernate-mapping>
employee.hbm.xml
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0">
  
<class name="EnPrint.DB.CEmployee,EnPrint.DB" table="Employee">  
    
<id name="ID" column="ID" type="Int32">
        
<generator class="identity" />
    
</id>    
    
<property name="Price" column="[Price]" type="Int32" />
    
<property name="Memo" column="[Memo]" type="string" length="50" /> 
    
<many-to-one name="Person" class="EnPrint.DB.CPerson,EnPrint.DB" column="Person_ID" unique="true" />    
  
</class>
</hibernate-mapping>

以下是使用nUnit的部分测试代码
            CEmployee employee = new CEmployee();
            employee.Price 
= 453;
            employee.Memo 
= "memo";

            CPerson person 
= new CPerson();
            person.Name 
= "employee kevin";
            person.Memo 
= "employee memo";
            employee.Person 
= person;
                
            
try
            
{
                
// Tell NHibernate that this object should be saved
                session.Save(person);//不执行会引起一个错误:
                                        
//EnPrint.DB.Test.EmployeeFixture.Add : 
                                        
//NHibernate.TransientObjectException : object references an 
                                        
//unsaved transient instance - save the transient instance 
                                        
//before flushing: EnPrint.DB.CPerson
                session.Save(employee);                    
                transaction.Commit();
            }

            
catch(Exception e)
            
{
                
if (transaction.WasRolledBack)
                    transaction.Rollback();
                
throw e;
            }

            
finally
            
{
                Console.Out.WriteLine(
string.Format("EmployeeID={0},PersonID={1}",
                    employee.ID,
                    employee.Person.ID));                
                session.Close();
            }

好了,唯一外键关联的相关内容完了,再倒过来看看主键关联。象上面的例子,其实Employee表完全没必在自己来生成编号,把Employee的ID字段删除是完全可以的。好,这时的没有自己主键的Employee与Person可以视为主键关联。来看看主键关联的映射文件。CPerson我还是不打算为他加上CEmployee成员,所以我们只需修改employee.hbm.xml文件
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0">
  
<class name="EnPrint.DB.CEmployee,EnPrint.DB" table="Employee">  
    
<id name="ID" column="Person_ID" type="Int32" unsaved-value="0">
        
<generator class="foreign">
         
<param name="property">Person</param>
      
</generator>
    
</id>    
    
<property name="Price" column="[Price]" type="Int32" />
    
<property name="Memo" column="[Memo]" type="string" length="50" /> 
    
<one-to-one name="Person" class="EnPrint.DB.CPerson,EnPrint.DB" cascade="all"/>  
  
</class>
</hibernate-mapping>

好了,测试的代码可以不修改,Person的ID值会保存到Employee的Person_ID中了。其实对于主键关联,session.Save(person)已是多余的了。只需session.Save(employee),person也会被同时保存起来。

外键关联需要执行四次数据查询语句,
NHibernate :INSERT INTO Person ([Name], [Memo]) VALUES (?, ?)
NHibernate :SELECT @@IDENTITY
NHibernate :INSERT INTO Employee ([Price], [Memo], Person_ID) VALUES (?, ?, ?)
NHibernate :SELECT @@IDENTITY

主键关系只需三次
NHibernate :INSERT INTO Person ([Name], [Memo]) VALUES (?, ?)
NHibernate :SELECT @@IDENTITY
NHibernate :INSERT INTO Employee ([Price], [Memo], Person_ID) VALUES (?, ?, ?)