您的位置:首页 > 其它

NHibernate的关联映射(one-to-one,one-to-many,many-to-many)以及cascade分析

2007-08-22 15:25 603 查看
NHibernate的关联映射(one-to-one,one-to-many,many-to-many)以及cascade分析
一、典型设置
cascade:(默认为none)级联。指明哪些操作会从对象级联到关联的对象。

inverse: (默认为false) 标记这个集合作为双向关联关系中的方向一端。在双向关联时才需要设置。在设为false的一端对cascade进行维护。处于性能的考虑,一般在数据少的一端或者被依赖端设置inverse="true",而让数据多的一段维护cascade。

1.one-to-one
1.1 数据库表结构
其中T_Person为主表,T_Employee为子表。T_Employee的PersonId参照T_Peson的PersonId。



1.2 示例映射类文件




/**//*


/*作者:DDL


/*联系:http://renrenqq.cnblogs.com/


*/




using System;




namespace DDLLY.TestNHibernate.TestAssociation.OneToOne






{




/**//// <summary>


///


/// </summary>


[Serializable]


public class Person






{




Private Members#region Private Members




private bool _isChanged;


private bool _isDeleted;


private int _personid;


private string _name;


private Employee _employee;




#endregion






Default ( Empty ) Class Constuctor#region Default ( Empty ) Class Constuctor






/**//// <summary>


/// default constructor


/// </summary>


public Person()






{


_personid = 0;


_name = null;


_employee = null;


}




#endregion // End of Default ( Empty ) Class Constuctor






Public Properties#region Public Properties






/**//// <summary>


///


/// </summary>


public virtual int PersonId






{




get

{ return _personid; }


set






{


_isChanged |= (_personid != value);


_personid = value;


}


}






/**//// <summary>


///


/// </summary>


public virtual string Name






{




get

{ return _name; }


set






{


if (value != null)


if (value.Length > 64)


throw new ArgumentOutOfRangeException("Invalid value for Name", value, value.ToString());




_isChanged |= (_name != value);


_name = value;


}


}






/**//// <summary>


///


/// </summary>


public Employee Employee






{




get

{ return _employee; }




set

{ _employee = value; }


}






/**//// <summary>


/// Returns whether or not the object has changed it's values.


/// </summary>


public bool IsChanged






{




get

{ return _isChanged; }


}






/**//// <summary>


/// Returns whether or not the object has changed it's values.


/// </summary>


public bool IsDeleted






{




get

{ return _isDeleted; }


}




#endregion






Public Functions#region Public Functions






/**//// <summary>


/// mark the item as deleted


/// </summary>


public void MarkAsDeleted()






{


_isDeleted = true;


_isChanged = true;


}




#endregion






Equals And HashCode Overrides#region Equals And HashCode Overrides






/**//// <summary>


/// local implementation of Equals based on unique value members


/// </summary>


public override bool Equals(object obj)






{


if (this == obj) return true;


if ((obj == null) || (obj.GetType() != GetType())) return false;


Person castObj = (Person) obj;


return (castObj != null) &&


(_personid == castObj.PersonId);


}






/**//// <summary>


/// local implementation of GetHashCode based on unique value members


/// </summary>


public override int GetHashCode()






{


int hash = 57;


hash = 27*hash*_personid.GetHashCode();


return hash;


}




#endregion


}


}




/**//*


/*作者:DDL


/*联系:http://renrenqq.cnblogs.com/


*/




using System;




namespace DDLLY.TestNHibernate.TestAssociation.OneToOne






{




/**//// <summary>


///


/// </summary>


[Serializable]


public class Employee






{




Private Members#region Private Members




private bool _isChanged;


private bool _isDeleted;


private int _personid;


private string _job;


private Person _person;




#endregion






Default ( Empty ) Class Constuctor#region Default ( Empty ) Class Constuctor






/**//// <summary>


/// default constructor


/// </summary>


public Employee()






{


_personid = 0;


_job = null;


_person = null;


}




#endregion // End of Default ( Empty ) Class Constuctor






Public Properties#region Public Properties






/**//// <summary>


///


/// </summary>


public virtual int PersonId






{




get

{ return _personid; }


set






{


_isChanged |= (_personid != value);


_personid = value;


}


}






/**//// <summary>


///


/// </summary>


public virtual string Job






{




get

{ return _job; }


set






{


if (value != null)


if (value.Length > 64)


throw new ArgumentOutOfRangeException("Invalid value for Job", value, value.ToString());




_isChanged |= (_job != value);


_job = value;


}


}




public Person Person






{




get

{ return _person; }




set

{ _person = value; }


}






/**//// <summary>


/// Returns whether or not the object has changed it's values.


/// </summary>


public bool IsChanged






{




get

{ return _isChanged; }


}






/**//// <summary>


/// Returns whether or not the object has changed it's values.


/// </summary>


public bool IsDeleted






{




get

{ return _isDeleted; }


}




#endregion






Public Functions#region Public Functions






/**//// <summary>


/// mark the item as deleted


/// </summary>


public void MarkAsDeleted()






{


_isDeleted = true;


_isChanged = true;


}




#endregion






Equals And HashCode Overrides#region Equals And HashCode Overrides






/**//// <summary>


/// local implementation of Equals based on unique value members


/// </summary>


public override bool Equals(object obj)






{


if (this == obj) return true;


if ((obj == null) || (obj.GetType() != GetType())) return false;


Employee castObj = (Employee) obj;


return (castObj != null) &&


(_personid == castObj.PersonId);


}






/**//// <summary>


/// local implementation of GetHashCode based on unique value members


/// </summary>


public override int GetHashCode()






{


int hash = 57;


hash = 27*hash*_personid.GetHashCode();


return hash;


}




#endregion


}


}
1.3 示例映射文件


<?xml version="1.0" encoding="utf-8" ?>


<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0">


<class name="DDLLY.TestNHibernate.TestAssociation.OneToOne.Person,DDLLY.TestNHibernate.TestAssociation" table="T_Person">




<id name="PersonId" column="PersonId" type="Int32" unsaved-value="0">


<generator class="native"/>


</id>


<property column="Name" type="String" name="Name" length="64" />




<one-to-one name="Employee" class="DDLLY.TestNHibernate.TestAssociation.OneToOne.Employee,DDLLY.TestNHibernate.TestAssociation" cascade="all"></one-to-one>




</class>


</hibernate-mapping>




<?xml version="1.0" encoding="utf-8" ?>


<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0">


<class name="DDLLY.TestNHibernate.TestAssociation.OneToOne.Employee,DDLLY.TestNHibernate.TestAssociation" table="T_Employee">




<id name="PersonId" column="PersonId" type="Int32" unsaved-value="0">


<generator class="foreign">


<param name="property">Person</param>


</generator>


</id>


<property column="Job" type="String" name="Job" length="64" />




<one-to-one name="Person" class="DDLLY.TestNHibernate.TestAssociation.OneToOne.Person,DDLLY.TestNHibernate.TestAssociation" constrained="true"></one-to-one>




</class>


</hibernate-mapping>



1.4 说明
constrained(约束): 表明该类对应的表对应的数据库表,和被关联的对象所对应的数据库表之间,通过一个外键引用对主键进行约束。这个选项影响Save()和Delete()在级联执行时的先后顺序(也在schema export tool中被使用)。

property-ref: (可选) 指定关联类的一个属性,这个属性将会和本外键相对应。如果没有指定,会使用对方关联类的主键。

<generator class="foreign">:表示使用另外一个相关联的对象的标识符,来创建主健。T_Employee的PersonId来自T_Person的ParentId。
Employee依赖于Person,所以通常在Person设置cascade。

2.另一种one-to-one
2.1数据库表结构
其中T_Person1为主表,T_Employee1为子表。T_Employee1的PersonId设置唯一约束,参照T_Person1的PersonId。



2.2示例映射类文件




/**//*


/*作者:DDL


/*联系:http://renrenqq.cnblogs.com/


*/




using System;




namespace DDLLY.TestNHibernate.TestAssociation.OneToOne1






{




/**//// <summary>


///


/// </summary>


[Serializable]


public class Person






{




Private Members#region Private Members




private bool _isChanged;


private bool _isDeleted;


private int _personid;


private string _name;


private Employee _employee;




#endregion






Default ( Empty ) Class Constuctor#region Default ( Empty ) Class Constuctor






/**//// <summary>


/// default constructor


/// </summary>


public Person()






{


_personid = 0;


_name = null;


_employee = null;


}




#endregion // End of Default ( Empty ) Class Constuctor






Public Properties#region Public Properties






/**//// <summary>


///


/// </summary>


public virtual int PersonId






{




get

{ return _personid; }


set






{


_isChanged |= (_personid != value);


_personid = value;


}


}






/**//// <summary>


///


/// </summary>


public virtual string Name






{




get

{ return _name; }


set






{


if (value != null)


if (value.Length > 64)


throw new ArgumentOutOfRangeException("Invalid value for Name", value, value.ToString());




_isChanged |= (_name != value);


_name = value;


}


}






/**//// <summary>


///


/// </summary>


public Employee Employee






{




get

{ return _employee; }




set

{ _employee = value; }


}






/**//// <summary>


/// Returns whether or not the object has changed it's values.


/// </summary>


public bool IsChanged






{




get

{ return _isChanged; }


}






/**//// <summary>


/// Returns whether or not the object has changed it's values.


/// </summary>


public bool IsDeleted






{




get

{ return _isDeleted; }


}




#endregion






Public Functions#region Public Functions






/**//// <summary>


/// mark the item as deleted


/// </summary>


public void MarkAsDeleted()






{


_isDeleted = true;


_isChanged = true;


}




#endregion






Equals And HashCode Overrides#region Equals And HashCode Overrides






/**//// <summary>


/// local implementation of Equals based on unique value members


/// </summary>


public override bool Equals(object obj)






{


if (this == obj) return true;


if ((obj == null) || (obj.GetType() != GetType())) return false;


Person castObj = (Person) obj;


return (castObj != null) &&


(_personid == castObj.PersonId);


}






/**//// <summary>


/// local implementation of GetHashCode based on unique value members


/// </summary>


public override int GetHashCode()






{


int hash = 57;


hash = 27*hash*_personid.GetHashCode();


return hash;


}




#endregion


}


}




/**//*


/*作者:DDL


/*联系:http://renrenqq.cnblogs.com/


*/




using System;




namespace DDLLY.TestNHibernate.TestAssociation.OneToOne1






{




/**//// <summary>


///


/// </summary>


[Serializable]


public class Employee






{




Private Members#region Private Members




private bool _isChanged;


private bool _isDeleted;


private int _employeeId;


private string _job;


private Person _person;




#endregion






Default ( Empty ) Class Constuctor#region Default ( Empty ) Class Constuctor






/**//// <summary>


/// default constructor


/// </summary>


public Employee()






{


_employeeId = 0;


_job = null;


_person = null;


}




#endregion // End of Default ( Empty ) Class Constuctor






Public Properties#region Public Properties






/**//// <summary>


///


/// </summary>


public virtual int EmployeeId






{




get

{ return _employeeId; }


set






{


_isChanged |= (_employeeId != value);


_employeeId = value;


}


}






/**//// <summary>


///


/// </summary>


public virtual string Job






{




get

{ return _job; }


set






{


if (value != null)


if (value.Length > 64)


throw new ArgumentOutOfRangeException("Invalid value for Job", value, value.ToString());




_isChanged |= (_job != value);


_job = value;


}


}




public Person Person






{




get

{ return _person; }




set

{ _person = value; }


}






/**//// <summary>


/// Returns whether or not the object has changed it's values.


/// </summary>


public bool IsChanged






{




get

{ return _isChanged; }


}






/**//// <summary>


/// Returns whether or not the object has changed it's values.


/// </summary>


public bool IsDeleted






{




get

{ return _isDeleted; }


}




#endregion






Public Functions#region Public Functions






/**//// <summary>


/// mark the item as deleted


/// </summary>


public void MarkAsDeleted()






{


_isDeleted = true;


_isChanged = true;


}




#endregion






Equals And HashCode Overrides#region Equals And HashCode Overrides






/**//// <summary>


/// local implementation of Equals based on unique value members


/// </summary>


public override bool Equals(object obj)






{


if (this == obj) return true;


if ((obj == null) || (obj.GetType() != GetType())) return false;


Employee castObj = (Employee) obj;


return (castObj != null) &&


(_employeeId == castObj.EmployeeId);


}






/**//// <summary>


/// local implementation of GetHashCode based on unique value members


/// </summary>


public override int GetHashCode()






{


int hash = 57;


hash = 27*hash*_employeeId.GetHashCode();


return hash;


}




#endregion


}


}

2.3示例映射文件


<?xml version="1.0" encoding="utf-8" ?>


<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0">


<class name="DDLLY.TestNHibernate.TestAssociation.OneToOne1.Person,DDLLY.TestNHibernate.TestAssociation" table="T_Person1">




<id name="PersonId" column="PersonId" type="Int32" unsaved-value="0">


<generator class="native"/>


</id>


<property column="Name" type="String" name="Name" length="64" />




<one-to-one name="Employee" class="DDLLY.TestNHibernate.TestAssociation.OneToOne1.Employee,DDLLY.TestNHibernate.TestAssociation" cascade="all"></one-to-one>




</class>


</hibernate-mapping>




<?xml version="1.0" encoding="utf-8" ?>


<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0">


<class name="DDLLY.TestNHibernate.TestAssociation.OneToOne1.Employee,DDLLY.TestNHibernate.TestAssociation" table="T_Employee1">




<id name="EmployeeId" column="EmployeeId" type="Int32" unsaved-value="0">


<generator class="native"/>


</id>


<property column="Job" type="String" name="Job" length="64" />




<many-to-one name="Person" class="DDLLY.TestNHibernate.TestAssociation.OneToOne1.Person,DDLLY.TestNHibernate.TestAssociation" column="PersonId" unique="true"></many-to-one>




</class>


</hibernate-mapping>



2.4说明
这种one-to-one实际上是一种特殊的one-to-many,如果T_Employee1的PersonId不设置唯一约束,则可成为one-to-many。所以在T_Employee端设置many-to-one而不是one-to-one,记住要加上unique="true"表示唯一约束。

3.one-to-many
3.1 数据库表结构
T_Parent为主表,T_Child的ParentId参照T_Parent的ParentId。



注意:对于单向的one-to-many映射,cascade过程中会用到把T_Child表的ParentId设置为Null,所以ParentId应设为允许NULL;

而双向one-to-many映射,建议把T_Child的ParentI设置为不允许NULL

3.2 示例映射类文件(单向)




/**//*


/*作者:DDL


/*联系:http://renrenqq.cnblogs.com/


*/




using System;


using System.Collections;




namespace DDLLY.TestNHibernate.TestAssociation.OneToMany1






{




/**//// <summary>


///


/// </summary>


[Serializable]


public class Parent






{




Private Members#region Private Members




private bool _isChanged;


private bool _isDeleted;


private int _parentid;


private string _name;


private IList _children;




#endregion






Default ( Empty ) Class Constuctor#region Default ( Empty ) Class Constuctor






/**//// <summary>


/// default constructor


/// </summary>


public Parent()






{


_parentid = 0;


_name = null;


_children = new ArrayList();


}




#endregion // End of Default ( Empty ) Class Constuctor






Public Properties#region Public Properties






/**//// <summary>


///


/// </summary>


public virtual int ParentId






{




get

{ return _parentid; }


set






{


_isChanged |= (_parentid != value);


_parentid = value;


}


}






/**//// <summary>


///


/// </summary>


public virtual string Name






{




get

{ return _name; }


set






{


if (value != null)


if (value.Length > 64)


throw new ArgumentOutOfRangeException("Invalid value for Name", value, value.ToString());




_isChanged |= (_name != value);


_name = value;


}


}






/**//// <summary>


///


/// </summary>


public virtual IList Children






{




get

{ return _children; }


set






{


_isChanged |= (_children != value);


_children = value;


}


}






/**//// <summary>


/// Returns whether or not the object has changed it's values.


/// </summary>


public bool IsChanged






{




get

{ return _isChanged; }


}






/**//// <summary>


/// Returns whether or not the object has changed it's values.


/// </summary>


public bool IsDeleted






{




get

{ return _isDeleted; }


}




#endregion






Public Functions#region Public Functions






/**//// <summary>


/// mark the item as deleted


/// </summary>


public void MarkAsDeleted()






{


_isDeleted = true;


_isChanged = true;


}




#endregion






Equals And HashCode Overrides#region Equals And HashCode Overrides






/**//// <summary>


/// local implementation of Equals based on unique value members


/// </summary>


public override bool Equals(object obj)






{


if (this == obj) return true;


if ((obj == null) || (obj.GetType() != GetType())) return false;


Parent castObj = (Parent) obj;


return (castObj != null) &&


(_parentid == castObj.ParentId);


}






/**//// <summary>


/// local implementation of GetHashCode based on unique value members


/// </summary>


public override int GetHashCode()






{


int hash = 57;


hash = 27*hash*_parentid.GetHashCode();


return hash;


}




#endregion


}


}




/**//*


/*作者:DDL


/*联系:http://renrenqq.cnblogs.com/


*/




using System;




namespace DDLLY.TestNHibernate.TestAssociation.OneToMany1






{




/**//// <summary>


///


/// </summary>


[Serializable]


public class Child






{




Private Members#region Private Members




private bool _isChanged;


private bool _isDeleted;


private int _childid;


private string _name;


private int _parentid;




#endregion






Default ( Empty ) Class Constuctor#region Default ( Empty ) Class Constuctor






/**//// <summary>


/// default constructor


/// </summary>


public Child()






{


_childid = 0;


_name = null;


_parentid = 0;


}




#endregion // End of Default ( Empty ) Class Constuctor






Public Properties#region Public Properties






/**//// <summary>


///


/// </summary>


public virtual int ChildId






{




get

{ return _childid; }


set






{


_isChanged |= (_childid != value);


_childid = value;


}


}






/**//// <summary>


///


/// </summary>


public virtual string Name






{




get

{ return _name; }


set






{


if (value != null)


if (value.Length > 64)


throw new ArgumentOutOfRangeException("Invalid value for Name", value, value.ToString());




_isChanged |= (_name != value);


_name = value;


}


}






/**//// <summary>


///


/// </summary>


public virtual int ParentId






{




get

{ return _parentid; }


set






{


_isChanged |= (_parentid != value);


_parentid = value;


}


}






/**//// <summary>


/// Returns whether or not the object has changed it's values.


/// </summary>


public bool IsChanged






{




get

{ return _isChanged; }


}






/**//// <summary>


/// Returns whether or not the object has changed it's values.


/// </summary>


public bool IsDeleted






{




get

{ return _isDeleted; }


}




#endregion






Public Functions#region Public Functions






/**//// <summary>


/// mark the item as deleted


/// </summary>


public void MarkAsDeleted()






{


_isDeleted = true;


_isChanged = true;


}




#endregion






Equals And HashCode Overrides#region Equals And HashCode Overrides






/**//// <summary>


/// local implementation of Equals based on unique value members


/// </summary>


public override bool Equals(object obj)






{


if (this == obj) return true;


if ((obj == null) || (obj.GetType() != GetType())) return false;


Child castObj = (Child) obj;


return (castObj != null) &&


(_childid == castObj.ChildId);


}






/**//// <summary>


/// local implementation of GetHashCode based on unique value members


/// </summary>


public override int GetHashCode()






{


int hash = 57;


hash = 27*hash*_childid.GetHashCode();


return hash;


}




#endregion


}


}
3.3 示例映射文件(单向)


<?xml version="1.0" encoding="utf-8" ?>


<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0">


<class name="DDLLY.TestNHibernate.TestAssociation.OneToMany1.Parent,DDLLY.TestNHibernate.TestAssociation" table="T_Parent">




<id name="ParentId" column="ParentId" type="Int32" unsaved-value="0">


<generator class="native"/>


</id>


<property column="Name" type="String" name="Name" length="64" />




<bag name="Children" cascade="all" lazy="true">


<key column="ParentId"/>


<one-to-many class="DDLLY.TestNHibernate.TestAssociation.OneToMany1.Child,DDLLY.TestNHibernate.TestAssociation"/>


</bag>




</class>


</hibernate-mapping>




<?xml version="1.0" encoding="utf-8" ?>


<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0">


<class name="DDLLY.TestNHibernate.TestAssociation.OneToMany1.Child,DDLLY.TestNHibernate.TestAssociation" table="T_Child">




<id name="ChildId" column="ChildId" type="Int32" unsaved-value="0">


<generator class="native"/>


</id>


<property column="Name" type="String" name="Name" length="64" />


<property column="ParentId" type="Int32" name="ParentId"/>




</class>


</hibernate-mapping>



3.4 示例映射类文件(双向)




/**//*


/*作者:DDL


/*联系:http://renrenqq.cnblogs.com/


*/




using System;


using System.Collections;




namespace DDLLY.TestNHibernate.TestAssociation.OneToMany






{




/**//// <summary>


///


/// </summary>


[Serializable]


public class Parent






{




Private Members#region Private Members




private bool _isChanged;


private bool _isDeleted;


private int _parentid;


private string _name;


private IList _children;




#endregion






Default ( Empty ) Class Constuctor#region Default ( Empty ) Class Constuctor






/**//// <summary>


/// default constructor


/// </summary>


public Parent()






{


_parentid = 0;


_name = null;


_children = new ArrayList();


}




#endregion // End of Default ( Empty ) Class Constuctor






Public Properties#region Public Properties






/**//// <summary>


///


/// </summary>


public virtual int ParentId






{




get

{ return _parentid; }


set






{


_isChanged |= (_parentid != value);


_parentid = value;


}


}






/**//// <summary>


///


/// </summary>


public virtual string Name






{




get

{ return _name; }


set






{


if (value != null)


if (value.Length > 64)


throw new ArgumentOutOfRangeException("Invalid value for Name", value, value.ToString());




_isChanged |= (_name != value);


_name = value;


}


}






/**//// <summary>


///


/// </summary>


public virtual IList Children






{




get

{ return _children; }


set






{


_isChanged |= (_children != value);


_children = value;


}


}






/**//// <summary>


/// Returns whether or not the object has changed it's values.


/// </summary>


public bool IsChanged






{




get

{ return _isChanged; }


}






/**//// <summary>


/// Returns whether or not the object has changed it's values.


/// </summary>


public bool IsDeleted






{




get

{ return _isDeleted; }


}




#endregion






Public Functions#region Public Functions






/**//// <summary>


/// mark the item as deleted


/// </summary>


public void MarkAsDeleted()






{


_isDeleted = true;


_isChanged = true;


}




#endregion






Equals And HashCode Overrides#region Equals And HashCode Overrides






/**//// <summary>


/// local implementation of Equals based on unique value members


/// </summary>


public override bool Equals(object obj)






{


if (this == obj) return true;


if ((obj == null) || (obj.GetType() != GetType())) return false;


Parent castObj = (Parent) obj;


return (castObj != null) &&


(_parentid == castObj.ParentId);


}






/**//// <summary>


/// local implementation of GetHashCode based on unique value members


/// </summary>


public override int GetHashCode()






{


int hash = 57;


hash = 27*hash*_parentid.GetHashCode();


return hash;


}




#endregion


}


}




/**//*


/*作者:DDL


/*联系:http://renrenqq.cnblogs.com/


*/




using System;




namespace DDLLY.TestNHibernate.TestAssociation.OneToMany






{




/**//// <summary>


///


/// </summary>


[Serializable]


public class Child






{




Private Members#region Private Members




private bool _isChanged;


private bool _isDeleted;


private int _childid;


private string _name;


private Parent _parent;




#endregion






Default ( Empty ) Class Constuctor#region Default ( Empty ) Class Constuctor






/**//// <summary>


/// default constructor


/// </summary>


public Child()






{


_childid = 0;


_name = null;


_parent = null;


}




#endregion // End of Default ( Empty ) Class Constuctor






Public Properties#region Public Properties






/**//// <summary>


///


/// </summary>


public virtual int ChildId






{




get

{ return _childid; }


set






{


_isChanged |= (_childid != value);


_childid = value;


}


}






/**//// <summary>


///


/// </summary>


public virtual string Name






{




get

{ return _name; }


set






{


if (value != null)


if (value.Length > 64)


throw new ArgumentOutOfRangeException("Invalid value for Name", value, value.ToString());




_isChanged |= (_name != value);


_name = value;


}


}






/**//// <summary>


///


/// </summary>


public virtual Parent Parent






{




get

{ return _parent; }


set






{


_isChanged |= (_parent != value);


_parent = value;


}


}






/**//// <summary>


/// Returns whether or not the object has changed it's values.


/// </summary>


public bool IsChanged






{




get

{ return _isChanged; }


}






/**//// <summary>


/// Returns whether or not the object has changed it's values.


/// </summary>


public bool IsDeleted






{




get

{ return _isDeleted; }


}




#endregion






Public Functions#region Public Functions






/**//// <summary>


/// mark the item as deleted


/// </summary>


public void MarkAsDeleted()






{


_isDeleted = true;


_isChanged = true;


}




#endregion






Equals And HashCode Overrides#region Equals And HashCode Overrides






/**//// <summary>


/// local implementation of Equals based on unique value members


/// </summary>


public override bool Equals(object obj)






{


if (this == obj) return true;


if ((obj == null) || (obj.GetType() != GetType())) return false;


Child castObj = (Child) obj;


return (castObj != null) &&


(_childid == castObj.ChildId);


}






/**//// <summary>


/// local implementation of GetHashCode based on unique value members


/// </summary>


public override int GetHashCode()






{


int hash = 57;


hash = 27*hash*_childid.GetHashCode();


return hash;


}




#endregion


}


}
3.5 示例映射类文件(双向)


<?xml version="1.0" encoding="utf-8" ?>


<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0">


<class name="DDLLY.TestNHibernate.TestAssociation.OneToMany.Parent,DDLLY.TestNHibernate.TestAssociation" table="T_Parent">




<id name="ParentId" column="ParentId" type="Int32" unsaved-value="0">


<generator class="native"/>


</id>


<property column="Name" type="String" name="Name" length="64" />




<bag name="Children" cascade="all" inverse="true" lazy="true">


<key column="ParentId"/>


<one-to-many class="DDLLY.TestNHibernate.TestAssociation.OneToMany.Child,DDLLY.TestNHibernate.TestAssociation"/>


</bag>




</class>


</hibernate-mapping>




<?xml version="1.0" encoding="utf-8" ?>


<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0">


<class name="DDLLY.TestNHibernate.TestAssociation.OneToMany.Child,DDLLY.TestNHibernate.TestAssociation" table="T_Child">




<id name="ChildId" column="ChildId" type="Int32" unsaved-value="0">


<generator class="native"/>


</id>


<property column="Name" type="String" name="Name" length="64" />




<many-to-one name="Parent" column="ParentId" class="DDLLY.TestNHibernate.TestAssociation.OneToMany.Parent,DDLLY.TestNHibernate.TestAssociation" />




</class>


</hibernate-mapping>



3.6 说明
在NHibernate配置文件中使用<set>, <list>, <map>, <bag>, <array> 和 <primitive-array>等元素来定义集合。<bag>是典型的一个,代码中我们用IList和它对应。我们以后会详细讲集合这个话题。

lazy表示允许延迟加载。表示在需要使用时才加载需要的数据。例如使用lazy时我们Load一个Parent他的Children为空,只有我们访问它的某一个Child时数据才会被加载;而不设置lazy我们Load一个Parent时其Children将同时加载。注意:使用lazy加载必须保证对应ISession的打开,否则懒加载会失败。

one-to-many可以设置单向和双向映射,设置单向时Child一段不设置many-to-one,而设置了ParentId的属性。

双向映射需要设置inverse而单向不需要。

单项映射在cascade时会对把T_Child的ParentId使用Update为Null的操作。

建议尽量使用双向映射。

4.many-to-many
4.1 数据库表结构



4.2 示例映射类文件




/**//*


/*作者:DDL


/*联系:http://renrenqq.cnblogs.com/


*/




using System;


using System.Collections;




namespace DDLLY.TestNHibernate.TestAssociation.ManyToMany






{




/**//// <summary>


///


/// </summary>


[Serializable]


public class User






{




Private Members#region Private Members




private bool _isChanged;


private bool _isDeleted;


private int _userid;


private string _username;


private string _password;


private string _email;


private IList _roles;




#endregion






Default ( Empty ) Class Constuctor#region Default ( Empty ) Class Constuctor






/**//// <summary>


/// default constructor


/// </summary>


public User()






{


_userid = 0;


_username = null;


_password = null;


_email = null;


_roles = new ArrayList();


}




#endregion // End of Default ( Empty ) Class Constuctor






Public Properties#region Public Properties






/**//// <summary>


///


/// </summary>


public virtual int UserId






{




get

{ return _userid; }


set






{


_isChanged |= (_userid != value);


_userid = value;


}


}






/**//// <summary>


///


/// </summary>


public virtual string UserName






{




get

{ return _username; }


set






{


if (value != null)


if (value.Length > 64)


throw new ArgumentOutOfRangeException("Invalid value for UserName", value, value.ToString());




_isChanged |= (_username != value);


_username = value;


}


}






/**//// <summary>


///


/// </summary>


public virtual string Password






{




get

{ return _password; }


set






{


if (value != null)


if (value.Length > 32)


throw new ArgumentOutOfRangeException("Invalid value for Password", value, value.ToString());




_isChanged |= (_password != value);


_password = value;


}


}






/**//// <summary>


///


/// </summary>


public virtual string Email






{




get

{ return _email; }


set






{


if (value != null)


if (value.Length > 64)


throw new ArgumentOutOfRangeException("Invalid value for Email", value, value.ToString());




_isChanged |= (_email != value);


_email = value;


}


}




public IList Roles






{




get

{ return _roles; }




set

{ _roles = value; }


}






/**//// <summary>


/// Returns whether or not the object has changed it's values.


/// </summary>


public bool IsChanged






{




get

{ return _isChanged; }


}






/**//// <summary>


/// Returns whether or not the object has changed it's values.


/// </summary>


public bool IsDeleted






{




get

{ return _isDeleted; }


}




#endregion






Public Functions#region Public Functions






/**//// <summary>


/// mark the item as deleted


/// </summary>


public void MarkAsDeleted()






{


_isDeleted = true;


_isChanged = true;


}




#endregion






Equals And HashCode Overrides#region Equals And HashCode Overrides






/**//// <summary>


/// local implementation of Equals based on unique value members


/// </summary>


public override bool Equals(object obj)






{


if (this == obj) return true;


if ((obj == null) || (obj.GetType() != GetType())) return false;


User castObj = (User) obj;


return (castObj != null) &&


(_userid == castObj.UserId);


}






/**//// <summary>


/// local implementation of GetHashCode based on unique value members


/// </summary>


public override int GetHashCode()






{


int hash = 57;


hash = 27*hash*_userid.GetHashCode();


return hash;


}




#endregion


}


}




/**//*


/*作者:DDL


/*联系:http://renrenqq.cnblogs.com/


*/




using System;


using System.Collections;




namespace DDLLY.TestNHibernate.TestAssociation.ManyToMany






{




/**//// <summary>


///


/// </summary>


[Serializable]


public class Role






{




Private Members#region Private Members




private bool _isChanged;


private bool _isDeleted;


private int _roleid;


private string _rolename;


private IList _users;




#endregion






Default ( Empty ) Class Constuctor#region Default ( Empty ) Class Constuctor






/**//// <summary>


/// default constructor


/// </summary>


public Role()






{


_roleid = 0;


_rolename = null;


_users = new ArrayList();


}




#endregion // End of Default ( Empty ) Class Constuctor






Public Properties#region Public Properties






/**//// <summary>


///


/// </summary>


public virtual int RoleId






{




get

{ return _roleid; }


set






{


_isChanged |= (_roleid != value);


_roleid = value;


}


}






/**//// <summary>


///


/// </summary>


public virtual string RoleName






{




get

{ return _rolename; }


set






{


if (value != null)


if (value.Length > 64)


throw new ArgumentOutOfRangeException("Invalid value for RoleName", value, value.ToString());




_isChanged |= (_rolename != value);


_rolename = value;


}


}




public IList Users






{




get

{ return _users; }




set

{ _users = value; }


}






/**//// <summary>


/// Returns whether or not the object has changed it's values.


/// </summary>


public bool IsChanged






{




get

{ return _isChanged; }


}






/**//// <summary>


/// Returns whether or not the object has changed it's values.


/// </summary>


public bool IsDeleted






{




get

{ return _isDeleted; }


}




#endregion






Public Functions#region Public Functions






/**//// <summary>


/// mark the item as deleted


/// </summary>


public void MarkAsDeleted()






{


_isDeleted = true;


_isChanged = true;


}




#endregion






Equals And HashCode Overrides#region Equals And HashCode Overrides






/**//// <summary>


/// local implementation of Equals based on unique value members


/// </summary>


public override bool Equals(object obj)






{


if (this == obj) return true;


if ((obj == null) || (obj.GetType() != GetType())) return false;


Role castObj = (Role) obj;


return (castObj != null) &&


(_roleid == castObj.RoleId);


}






/**//// <summary>


/// local implementation of GetHashCode based on unique value members


/// </summary>


public override int GetHashCode()






{


int hash = 57;


hash = 27*hash*_roleid.GetHashCode();


return hash;


}




#endregion


}


}
4.3 示例映射文件


<?xml version="1.0" encoding="utf-8" ?>


<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0">


<class name="DDLLY.TestNHibernate.TestAssociation.ManyToMany.User,DDLLY.TestNHibernate.TestAssociation" table="T_User">




<id name="UserId" column="UserId" type="Int32" unsaved-value="0">


<generator class="native"/>


</id>


<property column="UserName" type="String" name="UserName" not-null="true" length="64" />


<property column="Password" type="String" name="Password" not-null="true" length="32" />


<property column="Email" type="String" name="Email" length="64" />




<bag name="Roles" table="T_User_Role" lazy="true">


<key column="UserId"/>


<many-to-many class="DDLLY.TestNHibernate.TestAssociation.ManyToMany.Role,DDLLY.TestNHibernate.TestAssociation" column="RoleId"/>


</bag>




</class>


</hibernate-mapping>




<?xml version="1.0" encoding="utf-8" ?>


<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0">


<class name="DDLLY.TestNHibernate.TestAssociation.ManyToMany.Role,DDLLY.TestNHibernate.TestAssociation" table="T_Role">




<id name="RoleId" column="RoleId" type="Int32" unsaved-value="0">


<generator class="native"/>


</id>


<property column="RoleName" type="String" name="RoleName" not-null="true" length="64" />




<bag name="Users" table="T_User_Role" lazy="true" inverse="true">


<key column="RoleId"/>


<many-to-many class="DDLLY.TestNHibernate.TestAssociation.ManyToMany.User,DDLLY.TestNHibernate.TestAssociation" column="UserId"/>


</bag>






</class>


</hibernate-mapping>



4.4 说明
many-to-many性能不佳,数据量大时应尽可能避免使用。并尽可能使用lazy="true"。

在数据量少的一端设置inverse="true",让数据量多的一段维护cascade。

二、cascade分析
1.总述
cascade:(默认为none)级联。指明哪些操作会从对象级联到关联的对象。

orphans:孤儿,没有夫对象的子对象。对于代码Child.Parent==null,对于数据库T_Child表中ParentId为Null的数据。

delete orphans表示cascade时删除孤儿。

一般系统中是不允许孤儿存在的,我们可以通过数据库的约束来限制孤儿,例如T_Child的ParentId设为Not NULL。

如果确实存在孤儿请考虑适合的cascade策略。

cascade类型对应操作
all
Save / Delete / Update
all-delete-orphanSave / Delete / Update + delete orphans
delete-orphanDelete + delete orphans
noneNo Cascades
deleteDelete
save-updateSave / Update
2.one-to-one

a.初始化数据
PersonIdNameJob
1DDL编程
2LLYNULL
b.测试方法
TestAddPersonWithAddEmployee


Person person = new Person();


person.Name = "newPerson";


Employee employee = new Employee();


employee.Job = "newJob";


person.Employee = employee;


employee.Person = person;




session.Save(person);



TestUpdatePersonWithAddEmployee


Person person = session.Load(typeof (Person), 2) as Person;


person.Employee = new Employee();


person.Employee.Person = person;


person.Employee.Job = "LLYJob";




session.Update(person);



TestUpdatePersonWithUpdateEmployee


Person person = session.Load(typeof (Person), 1) as Person;


person.Employee.Job = "DDL'New Job";




session.Update(person);



TestDeletePersonWithDeleteEmployee


Person person = session.Load(typeof (Person), 1) as Person;




session.Delete(person);



c.测试结果

测试方法

save-update

delete

delete-orphan

all

all-delete-orphan

none

TestAddPersonWithAddEmployee

Y

N

N

Y

Y

N

TestUpdatePersonWithAddEmployee

Y

N

N

Y

Y

N

TestUpdatePersonWithUpdateEmployee

Y

Y

Y

Y

Y

Y

TestDeletePersonWithDeleteEmployee

N

Y

Y

Y

Y

N

2.另一种one-to-one

a.初始化数据
PersonIdNameEmployeeIdJob
1DDL1编程
2LLYNULLNULL
b.测试方法

TestAddPersonWithAddEmployee

不支持

TestUpdatePersonWithAddEmployee


Person person = session.Load(typeof (Person), 2) as Person;


person.Employee = new Employee();


person.Employee.Person = person;


person.Employee.Job = "LLYJob";




session.Update(person);


session.Flush();



TestUpdatePersonWithUpdateEmployee


Person person = session.Load(typeof (Person), 1) as Person;


person.Employee.Job = "DDL'New Job";




session.Update(person);


session.Flush();



TestDeletePersonWithDeleteEmployee


Person person = session.Load(typeof (Person), 1) as Person;




session.Delete(person);


session.Flush();



c.测试结果

测试方法

save-update

delete

delete-orphan

all

all-delete-orphan

none

TestAddPersonWithAddEmployee

不支持

不支持

不支持

不支持

不支持

不支持

TestUpdatePersonWithAddEmployee

Y

N

N

Y

Y

N

TestUpdatePersonWithUpdateEmployee

Y

Y

Y

Y

Y

Y

TestDeletePersonWithDeleteEmployee

N

Y

Y

Y

Y

N

3.one-to-many(双向)

a.初始化数据
ParentIdParentNameChildIdChildName
1Parent11Child1
2Parent2NULLNULL
b.测试方法
TestAddParentWithAddChild


Parent parent = new Parent();


parent.Name = "NewParent";




Child child = new Child();


child.Name = "NewChild";


child.Parent = parent;




parent.Children.Add(child);




session.Save(parent);


session.Flush();



TestUpdateParentWithAddChild


Parent parent = session.Load(typeof (Parent), 2) as Parent;




Child child = new Child();


child.Name = "NewChild";


child.Parent = parent;




parent.Children.Add(child);




session.Update(parent);




session.Flush();



TestUpdateParentWithUpdateChild


Parent parent = session.Load(typeof (Parent), 1) as Parent;




Child child = (Child) parent.Children[0];




child.Name = "UpdateName";




session.Update(parent);




session.Flush();



TestDeleteParentWithChild


Parent parent = session.Load(typeof (Parent), 1) as Parent;




session.Delete(parent);


session.Flush();



c.测试结果

测试方法

save-update

delete

delete-orphan

all

all-delete-orphan

none

TestAddParentWithAddChildYNNYYN
TestUpdateParentWithAddChildYNNYYN
TestUpdateParentWithUpdateChildYYYYYY
TestDeleteParentWithChildNYYYYN
4.one-to-many(单向)

a.初始化数据
同上

b.测试方法
TestAddParentWithAddChild

不支持

TestUpdateParentWithAddChild


Parent parent = session.Load(typeof (Parent), 2) as Parent;




Child child = new Child();


child.Name = "NewChild";


child.ParentId = parent.ParentId;




parent.Children.Add(child);




session.Update(parent);




session.Flush();



TestUpdateParentWithUpdateChild


Parent parent = session.Load(typeof (Parent), 1) as Parent;




Child child = (Child) parent.Children[0];




child.Name = "UpdateName";




session.Update(parent);




session.Flush();



TestDeleteParentWithChild


Parent parent = session.Load(typeof (Parent), 1) as Parent;




session.Delete(parent);




session.Flush();



c.测试结果

测试方法

save-update

delete

delete-orphan

all

all-delete-orphan

none

TestAddParentWithAddChild不支持不支持不支持不支持不支持不支持
TestUpdateParentWithAddChildYNNYYN
TestUpdateParentWithUpdateChildYYYYYY
TestDeleteParentWithChildParent被删除,Child成为孤儿YYYYParent被删除,Child成为孤儿
5.many-to-many
many-to-many和别的关联映射有所不同。例子中:Role和User没有直接的依赖关系,而是通过一张中间表完成。在删除User时一般不会要求删除Role,而是删除之间的关系(即从中间表删除数据)。

a.初始化数据
UserIdUserNamePasswordEmailRoleIdRoleName
1DDL1NULL1角色1
1DDL1NULL2角色2
2LLY2NULL1角色1
3陌生人3NULLNULLNULL
NULLNULLNULLNULL3角色3
b.测试方法
TestAddRoleToUser


User user = session.Load(typeof (User), 1) as User;


Role role = session.Load(typeof (Role), 3) as Role;




user.Roles.Add(role);


role.Users.Add(user);




session.Update(user);


session.Flush();



TestRemoveRoleFromUser


User user = session.Load(typeof (User), 1) as User;


Role role = session.Load(typeof (Role), 2) as Role;




user.Roles.Remove(role);


role.Users.Remove(user);




session.Update(user);


session.Flush();







TestUpdateUserWithRole


User user = session.Load(typeof(User), 2) as User;


((Role) user.Roles[0]).RoleName = "UpdateRole";




session.Update(user);


session.Flush();



TestDeleteUserWithSetRole


User user = session.Load(typeof (User), 1) as User;


session.Delete(user);


session.Flush();
c.测试结果

测试方法

save-update

delete

delete-orphan

all

all-delete-orphan

none

TestAddRoleToUserYYYYYY
TestRemoveRoleFromUserYYYYYY
TestUpdateUserWithRoleYYYYYY
TestDeleteUserWithSetRoleNUer被删除,但和其有关的Role也被删除Uer被删除,但和其有关的Role也被删除Uer被删除,但和其有关的Role也被删除Uer被删除,但和其有关的Role也被删除N
三、结论

关联是NHibernate里面功能很强的一块,但也使很容易滥用而造成引起性能或其他问题的地方。所以请慎重的使用。

在使用之前,请考虑好以下问题:

1.关系分析,一对多,多对多,还是一对一。

2.确定依赖关系,例如:Child依赖于Parent。

3.是否允许存在孤儿,例如:存在Child没有Parent(即在数据库中ParentId为Null的Child)。

4.在对等的关系中是否有主动端。例如:需要给Parent设置Child还是给Child找Parent,或者两边都可以操作。

5.关联两端可能出现的数据量以及在页面显示时是否分页。如果数据量大或者页面上需要分页显示,建议不要采用关联映射。如果数据量大,性能会不好,如果需要分页,关联所有数据似乎没有什么意思。

6.页面上可能的对象操作方法。例如:先读取一个Parent,然后添加Child,然后保存。

请根据你的情况设置关联映射,而对于cascade标准的设置可以满足绝大多数的需要,如一有特殊情况,请按照上面的分析选择合适的。

下载代码
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: