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是可以單獨使用的, 我們建議只要是子表, 就應該使用, 這樣可以保證數據的完整性. 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章