博客园有不少优秀的NHibernate起步的教程,但很多的都是官方StartKit的教程,关于如何来解决初学者所遇到的问题上,以及对NHibernate使用中一些关键点如何理解上所述甚少。本文是我自己在学习NHiberNate中所遇到的一些关键点以及一些问题的记录。希望对我或与我有相同困惑的人有所帮助。

 

写了一个示例程序,来实现Many2One,示例程序组成:Order与OrderDetail,对应的Hbm与cs文件如下:

数据库如下:

)


 Order.hbm.xml

NHibernate学习之一:Many2One遇到的问题<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
NHibernate学习之一:Many2One遇到的问题
NHibernate学习之一:Many2One遇到的问题  
<class name="NHibernateStudy.Domain.Order, NHibernateStudy.Domain" table="TBL_ORDER"
NHibernate学习之一:Many2One遇到的问题     lazy
="false">
NHibernate学习之一:Many2One遇到的问题    
<id name="Id" column="ID" type="Guid"
NHibernate学习之一:Many2One遇到的问题        unsaved-value
="00000000-0000-0000-0000-000000000000">
NHibernate学习之一:Many2One遇到的问题      
<generator class="guid" />
NHibernate学习之一:Many2One遇到的问题    
</id>
NHibernate学习之一:Many2One遇到的问题
NHibernate学习之一:Many2One遇到的问题    
<property name="UserName" column="USERNAME" type="String" length="40"/>
NHibernate学习之一:Many2One遇到的问题    
<property name="OrderTime" column="ORDERTIME" type="DateTime"></property>
NHibernate学习之一:Many2One遇到的问题    
<property name="TotalAmount" column="TOTALAMOUNT" type="Decimal"/>
NHibernate学习之一:Many2One遇到的问题
NHibernate学习之一:Many2One遇到的问题    
<bag name="Items" lazy="true" inverse="true" cascade="all-delete-orphan">
NHibernate学习之一:Many2One遇到的问题      
<key column="ORDER_ID"></key>
NHibernate学习之一:Many2One遇到的问题      
<one-to-many class="NHibernateStudy.Domain.OrderDetail, NHibernateStudy.Domain"/>
NHibernate学习之一:Many2One遇到的问题      
NHibernate学习之一:Many2One遇到的问题    
</bag>   
NHibernate学习之一:Many2One遇到的问题  
</class>
NHibernate学习之一:Many2One遇到的问题
NHibernate学习之一:Many2One遇到的问题
</hibernate-mapping>
NHibernate学习之一:Many2One遇到的问题
NHibernate学习之一:Many2One遇到的问题

OrderDetail.hbm.xml

NHibernate学习之一:Many2One遇到的问题<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
NHibernate学习之一:Many2One遇到的问题
NHibernate学习之一:Many2One遇到的问题  
<class name="NHibernateStudy.Domain.OrderDetail, NHibernateStudy.Domain" table="TBL_ORDER_DETAIL"
NHibernate学习之一:Many2One遇到的问题     lazy
="false">
NHibernate学习之一:Many2One遇到的问题    
<id name="Id" column="ID" type="Guid"
NHibernate学习之一:Many2One遇到的问题        unsaved-value
="00000000-0000-0000-0000-000000000000">
NHibernate学习之一:Many2One遇到的问题      
<generator class="guid" />
NHibernate学习之一:Many2One遇到的问题    
</id>
NHibernate学习之一:Many2One遇到的问题    
<many-to-one name="Order" class ="NHibernateStudy.Domain.Order, NHibernateStudy.Domain" column="ORDER_ID" not-null="true"/>
NHibernate学习之一:Many2One遇到的问题    
NHibernate学习之一:Many2One遇到的问题    
NHibernate学习之一:Many2One遇到的问题    
<property name="ItemName" column="ITEM_NAME" type="String" length="40"/>
NHibernate学习之一:Many2One遇到的问题    
<property name="Amount" column="AMOUNT" type="Decimal"/>
NHibernate学习之一:Many2One遇到的问题    
NHibernate学习之一:Many2One遇到的问题  
</class>
NHibernate学习之一:Many2One遇到的问题
NHibernate学习之一:Many2One遇到的问题
</hibernate-mapping>
NHibernate学习之一:Many2One遇到的问题
NHibernate学习之一:Many2One遇到的问题

Order.cs

OrderDetail.cs


 

在写程序中共遇到如下的疑惑处,均已经解决。现记录如下

第一点:写Hbm中遇到的问题 

实现Many2One有两种实现方法,一种是只在父类的Hbm中增加信息,不改变子表的Hbm的信息。但这种方法有如下缺点

1) 子表中父表的关联字段即FK不可为空

2) 在每次更新子表的时候都是分两步走的Insert然后Update,存在效率问题,且第一次Insert的时候FK为空。

    由于存在这两个方面的问题,所以一般不采用这种方法。关于上面两个缺陷请看下文(下文来自NHiberNate的自带文档)

NHibernate学习之一:Many2One遇到的问题Suppose we start with a simple <one-to-many> association from Parent to Child. 
NHibernate学习之一:Many2One遇到的问题
<set name="Children">
NHibernate学习之一:Many2One遇到的问题    
<key column="parent_id" />
NHibernate学习之一:Many2One遇到的问题    
<one-to-many class="Child" />
NHibernate学习之一:Many2One遇到的问题
</set>
NHibernate学习之一:Many2One遇到的问题If we were to execute the following code 
NHibernate学习之一:Many2One遇到的问题Parent p 
= NHibernate学习之一:Many2One遇到的问题..;
NHibernate学习之一:Many2One遇到的问题Child c 
= new Child();
NHibernate学习之一:Many2One遇到的问题p.Children.Add(c);
NHibernate学习之一:Many2One遇到的问题session.Save(c);
NHibernate学习之一:Many2One遇到的问题session.Flush();
NHibernate学习之一:Many2One遇到的问题NHibernate would issue two SQL statements: 
NHibernate学习之一:Many2One遇到的问题an INSERT to create the record 
for c
NHibernate学习之一:Many2One遇到的问题an UPDATE to create the link from p to c 
NHibernate学习之一:Many2One遇到的问题This 
is not only inefficient, but also violates any NOT NULL constraint on the parent_id column.
NHibernate学习之一:Many2One遇到的问题

所以一般采用第二种方法,我自己写的示例程序也是采用这种方法的。 

首先看条目类的HBM文件,在子类的hbm文件加入:

NHibernate学习之一:Many2One遇到的问题<many-to-one name="Order" class ="NHibernateStudy.Domain.Order, NHibernateStudy.Domain" column="ORDER_ID" not-null="true"/>

 

备注:

1)     条目类的Hbm文件用many-to-one来与主类相联系

2)     name属性,表示在条目类中,主类的Properties名称

3)     class属性,表示主类的类名,与名称空间

4)     column属性,表示在条目类对应的条目表中与主类对应的父表关联字段。简单点说就是条目表中对应主表的那个外键

5)     not-null属性,表示是否为空。

 

看主类的HBM文件,在主类的Hbm文件加入

NHibernate学习之一:Many2One遇到的问题<bag name="Items" lazy="true" inverse="true" cascade="all-delete-orphan">
NHibernate学习之一:Many2One遇到的问题
NHibernate学习之一:Many2One遇到的问题      
<key column="ORDER_ID"></key>
NHibernate学习之一:Many2One遇到的问题
NHibernate学习之一:Many2One遇到的问题      
<one-to-many class="NHibernateStudy.Domain.OrderDetail, NHibernateStudy.Domain"/>
NHibernate学习之一:Many2One遇到的问题
NHibernate学习之一:Many2One遇到的问题
</bag>
NHibernate学习之一:Many2One遇到的问题
NHibernate学习之一:Many2One遇到的问题

关于用哪种表示集合,见下面的(http://wljcan.cnblogs.com/archive/2004/06/30/19713.html)

 

NHibernate学习之一:Many2One遇到的问题在Nhibernate中经常遇到one-to-many和many-to-many的关系映射,用一些集合类来保存关联的many集合,这些集合类包括: IList、Array和IDictionary。其在map文件中对应的元素为 list(IList)、set(IDictionary)、bag(IList)、map(IDictionary)和array(Array)。
NHibernate学习之一:Many2One遇到的问题
NHibernate学习之一:Many2One遇到的问题        其中比较特殊的是List和Array,它们需要在关联表中用一个单独字段来保存列表(List)或数组(Array)的索引(如childRecord[i]中的i),虽然list可以实现对无序元素的访问,但是在nhibernate中还是必须要提供索引。这样就出现一个问题:如果表中没有这样的index字段,将无法使用array,这样可能降低性能,因为使用IList的时候需要 boxing 和unboxing。
NHibernate学习之一:Many2One遇到的问题
NHibernate学习之一:Many2One遇到的问题   
NHibernate学习之一:Many2One遇到的问题
NHibernate学习之一:Many2One遇到的问题        另外,在使用的过程中发现使用 list无法与datagrid绑定,而bag却可以。
NHibernate学习之一:Many2One遇到的问题
NHibernate学习之一:Many2One遇到的问题       
<bag name="Students" lazy="true" inverse="true" >
NHibernate学习之一:Many2One遇到的问题
NHibernate学习之一:Many2One遇到的问题          
<key column="TeacherID"/> 
NHibernate学习之一:Many2One遇到的问题
NHibernate学习之一:Many2One遇到的问题          
<one-to-many class="testMSSql.student, testMSSql" />
NHibernate学习之一:Many2One遇到的问题
NHibernate学习之一:Many2One遇到的问题        
</bag>
NHibernate学习之一:Many2One遇到的问题
NHibernate学习之一:Many2One遇到的问题 
NHibernate学习之一:Many2One遇到的问题
NHibernate学习之一:Many2One遇到的问题       
<list name="Students" lazy="true" inverse="true" >
NHibernate学习之一:Many2One遇到的问题
NHibernate学习之一:Many2One遇到的问题          
<key column="TeacherID"/> 
NHibernate学习之一:Many2One遇到的问题
NHibernate学习之一:Many2One遇到的问题          
<index column="id" />
NHibernate学习之一:Many2One遇到的问题
NHibernate学习之一:Many2One遇到的问题          
<one-to-many class="testMSSql.student, testMSSql" />
NHibernate学习之一:Many2One遇到的问题
NHibernate学习之一:Many2One遇到的问题        
</list>
NHibernate学习之一:Many2One遇到的问题
NHibernate学习之一:Many2One遇到的问题 
NHibernate学习之一:Many2One遇到的问题
NHibernate学习之一:Many2One遇到的问题

备注:1)<bag>表示集合,集合的区别见上

        2)lazy = true,表示延迟加载。经试验,此处的lazy与下面的lazy是有区别的

 

NHibernate学习之一:Many2One遇到的问题<class name="NHibernateStudy.Domain.OrderDetail, NHibernateStudy.Domain" table="TBL_ORDER_DETAIL"     lazy="false">

 

如果在类中写 lazy= true,那么此类的所有属性均要为 public virtual。而在关联时,写上lazy=true,则无此要求。但按照建议,还是将类的所有属性写成virtual要好。

3) inverse = true,表示将主类与条目类之间的关系控制移交给条目类来完成。即

NHibernate学习之一:Many2One遇到的问题Parent p = (Parent) session.Load(typeof(Parent), pid);
NHibernate学习之一:Many2One遇到的问题
NHibernate学习之一:Many2One遇到的问题Child c 
= new Child();
NHibernate学习之一:Many2One遇到的问题
NHibernate学习之一:Many2One遇到的问题c.Parent 
= p;
NHibernate学习之一:Many2One遇到的问题
NHibernate学习之一:Many2One遇到的问题p.Children.Add(c);
NHibernate学习之一:Many2One遇到的问题
NHibernate学习之一:Many2One遇到的问题session.Save(c);
NHibernate学习之一:Many2One遇到的问题
NHibernate学习之一:Many2One遇到的问题session.Flush();
NHibernate学习之一:Many2One遇到的问题
NHibernate学习之一:Many2One遇到的问题

必须要写 c.Parent = p;来完成主类与条目类之间的关系,没有此语句,仅仅将条目类放入主类中的语句p.Children.Add(c),无法完成主类与条目类的关联。

为了简化这个过程,可以在主类中加入如下函数

NHibernate学习之一:Many2One遇到的问题public void AddChild(Child c)

4) cascade表示级联使用的场合

5) 属性 Key column表示主表与条目表的关联字段。记住是这个关联字段在条目表中的名称。即无论是bag中还是条目类的hbm文件中的many-to-one中所指定的column都是指条目表中外键字段的名称。

6) 属性one-to-many,指定条目类

第二点: 写程序中遇到的问题

1) 在条目类中放入一个引用的主类的变量。变量名称即为在条目类中many-to-one中name属性指定的值。刚开始由于还是以数据库的思维考虑,放入了一个主类的ID,汗一个。

2) 父类中放一个条目类的IList。在父类中使用范型的ILIst来完成条目类的引用效率更高,相关代码如下:

NHibernate学习之一:Many2One遇到的问题using System.Collections.Generic;
NHibernate学习之一:Many2One遇到的问题
NHibernate学习之一:Many2One遇到的问题
private IList<OrderDetail> itmes;
NHibernate学习之一:Many2One遇到的问题
NHibernate学习之一:Many2One遇到的问题
public virtual IList<OrderDetail> Items
NHibernate学习之一:Many2One遇到的问题

3) 在父类的构造函数中要建立子类所用的IList实例。刚开始,忘记new此实例导致在加入条目类的时候出现空引用。代码如下:

NHibernate学习之一:Many2One遇到的问题public Order()
NHibernate学习之一:Many2One遇到的问题

3) 编译时遇到的问题

1) 是遇到空引用的问题,问题源自2-3

出现了 mappingException,找不到对应的EntityClass。――未将对应的hbm文件作为嵌入资源。即设置文件*.hbm.xml的生成操作属性为“嵌入的资源”。感谢(http://www.cnblogs.com/david-chan/archive/2006/02/18/333230.aspx

相关文章:

  • 2021-12-12
  • 2022-12-23
  • 2021-05-04
  • 2021-12-18
  • 2021-12-18
  • 2021-07-29
  • 2021-10-23
  • 2021-07-10
猜你喜欢
  • 2021-05-25
  • 2022-12-23
  • 2021-09-19
  • 2021-11-07
  • 2020-05-31
  • 2021-11-05
  • 2022-01-17
相关资源
相似解决方案