nhibernate入門系列: one-to-many映射
數據庫中的主從表就是一對多的關係了,這種關係在按範式設計的數據庫中是十分常見的.在nh中,通過one-to-many映射可以十分方便的處理這種關係,包括級聯更新,刪除等. 下面以一個簡單的主從表來說明one-to-many的應用.
先來看看Parent類的映射信息:
<class name="Parent, assemblyname" table="Parents">
<id type="Int32" column="parent_id" unsaved-value="0" name="ParentId">
<generator class="identity" />
</id>
<property type="String" column="Name" name="Name"/>
<set name="Childs" cascade="all" inverse="true" lazy="false">
<key column="parent_id" />
<one-to-many class="Child, AssemblyName" />
</set>
</class>
one-to-many關係必須通過一個nh的集合類型來定義, 這裏使用set.
在上面的映射文件中,定義級聯類型爲all,允許所有持久化操作級聯到子類;inverse標記這個集合爲雙向關聯中的一端;lazy爲延遲加載(使用此特性時一定在注意會話的生存週期)。
key column爲與子類關聯的鍵列,這裏爲Parent的主鍵parent_id。
Parent的定義:
public class Parent {
public Parent() {
}
public int ParentId {
get { return parentId; }
set { parentId = value; }
}
public string Name {
get { return name; }
set { name = value; }
}
public IDictionary Childs {
get { return childs; }
set { childs = value; }
}
private int parentId;
private string name;
private IDictionary childs = new Hashtable();
} //class Parent
這裏用一個數據字典(Dictionary)對象來保存由set集合指定的子對象;
再來看看Child類的映射信息:
<class name="Child, AssemblyName" table="Childs">
<id type="Int32" column="child_id" unsaved-value="0" name="ChildId">
<generator class="identity" />
</id>
<property type="String" column="Name" name="Name"/>
<many-to-one
name="Parent"
column="parent_id"
class="Parent, AssemblyName"
unique="true"
/>
</class>
在many-to-one定義中,定義了與parent關聯的列parent_id以及父類名稱;unique指定與子類關聯的父類是唯一的
這裏並沒有單獨映射parent_id列,此列映射信息由many-to-one定義給出, 這樣可以保證數據完整性.
Child 類的定義:
public class Child {
public Child() {
}
public int childId {
get { return childId; }
set { childId = value; }
}
public string Name {
get { return name; }
set { name = value; }
}
public Parent Parent {
get {
if ( parent == null ) parent = new Hashtable();
return parent;
}
set { parent = value; }
}
private int childId;
private string name;
private Parent parent;
} //class Child
下面給出了部分測試代碼。
public TestCreate() {
Parent parent = new Parent();
parent.Name = "test parent";
Child child = new Child();
child.Name = "test child";
child.Parent = parent; // 必須設置父對象才能正確保存!
parent.Childs.Add( child, child );
session.Save( parent );
}
public TestRemoveChild() {
Parent parent = new Parent();
parent.Name = "test parent";
Child child = new Child();
child.Name = "test child";
child.Parent = parent;
Child child2 = new Child();
child2.Name = "test child2";
child2.Parent = parent;
parent.Childs.Add( child, child );
parent.Childs.Add( child2, child2 );
session.Save( parent );
session.Close();
int parentId = parent.ParentId;
parent = (Parent)session.load( typeof(Parent), parentId )
IDictionaryEnumerator e = parent.Childs.GetEnumerator();
if ( e.MoveNext )
{
Child child3 = (Child)e.Key;
parent.Childs.Remove ( child3 ); // 刪除只是斷開子類與父類的關聯,並不會真正刪除!
Session.Delete( child3 ); // 此處代碼未測試正確性。
// Session.Save( parent );
}
}
以上測試代碼中session的相關操作請查看相關文檔。
在使用one-to-many時, 因爲子對象是隨父對象一起加載的(使用lazy除外), 這在有些時候就不是很有必要了, 並且產生性能問題, 在實際應用中應該要考慮清楚.
而many-to-one是可以單獨使用的, 我們建議只要是子表, 就應該使用, 這樣可以保證數據的完整性.
先來看看Parent類的映射信息:
<class name="Parent, assemblyname" table="Parents">
<id type="Int32" column="parent_id" unsaved-value="0" name="ParentId">
<generator class="identity" />
</id>
<property type="String" column="Name" name="Name"/>
<set name="Childs" cascade="all" inverse="true" lazy="false">
<key column="parent_id" />
<one-to-many class="Child, AssemblyName" />
</set>
</class>
one-to-many關係必須通過一個nh的集合類型來定義, 這裏使用set.
在上面的映射文件中,定義級聯類型爲all,允許所有持久化操作級聯到子類;inverse標記這個集合爲雙向關聯中的一端;lazy爲延遲加載(使用此特性時一定在注意會話的生存週期)。
key column爲與子類關聯的鍵列,這裏爲Parent的主鍵parent_id。
Parent的定義:
public class Parent {
public Parent() {
}
public int ParentId {
get { return parentId; }
set { parentId = value; }
}
public string Name {
get { return name; }
set { name = value; }
}
public IDictionary Childs {
get { return childs; }
set { childs = value; }
}
private int parentId;
private string name;
private IDictionary childs = new Hashtable();
} //class Parent
這裏用一個數據字典(Dictionary)對象來保存由set集合指定的子對象;
再來看看Child類的映射信息:
<class name="Child, AssemblyName" table="Childs">
<id type="Int32" column="child_id" unsaved-value="0" name="ChildId">
<generator class="identity" />
</id>
<property type="String" column="Name" name="Name"/>
<many-to-one
name="Parent"
column="parent_id"
class="Parent, AssemblyName"
unique="true"
/>
</class>
在many-to-one定義中,定義了與parent關聯的列parent_id以及父類名稱;unique指定與子類關聯的父類是唯一的
這裏並沒有單獨映射parent_id列,此列映射信息由many-to-one定義給出, 這樣可以保證數據完整性.
Child 類的定義:
public class Child {
public Child() {
}
public int childId {
get { return childId; }
set { childId = value; }
}
public string Name {
get { return name; }
set { name = value; }
}
public Parent Parent {
get {
if ( parent == null ) parent = new Hashtable();
return parent;
}
set { parent = value; }
}
private int childId;
private string name;
private Parent parent;
} //class Child
下面給出了部分測試代碼。
public TestCreate() {
Parent parent = new Parent();
parent.Name = "test parent";
Child child = new Child();
child.Name = "test child";
child.Parent = parent; // 必須設置父對象才能正確保存!
parent.Childs.Add( child, child );
session.Save( parent );
}
public TestRemoveChild() {
Parent parent = new Parent();
parent.Name = "test parent";
Child child = new Child();
child.Name = "test child";
child.Parent = parent;
Child child2 = new Child();
child2.Name = "test child2";
child2.Parent = parent;
parent.Childs.Add( child, child );
parent.Childs.Add( child2, child2 );
session.Save( parent );
session.Close();
int parentId = parent.ParentId;
parent = (Parent)session.load( typeof(Parent), parentId )
IDictionaryEnumerator e = parent.Childs.GetEnumerator();
if ( e.MoveNext )
{
Child child3 = (Child)e.Key;
parent.Childs.Remove ( child3 ); // 刪除只是斷開子類與父類的關聯,並不會真正刪除!
Session.Delete( child3 ); // 此處代碼未測試正確性。
// Session.Save( parent );
}
}
以上測試代碼中session的相關操作請查看相關文檔。
在使用one-to-many時, 因爲子對象是隨父對象一起加載的(使用lazy除外), 這在有些時候就不是很有必要了, 並且產生性能問題, 在實際應用中應該要考慮清楚.
而many-to-one是可以單獨使用的, 我們建議只要是子表, 就應該使用, 這樣可以保證數據的完整性.
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.