1)one-to-one
2)one-to-many / many-to-one
3)many-to-many
因爲官方文檔介紹得很少,學起來非常費勁,我在這裏做一個學習總結,希望能引起大家的繼續討論。
爲了便於描述。,本系列學習手記將引入Category和Item對象,分別實現以下關係:
1)Category和Item對象之前不存在關係(none-association);
2)Category和Item對象之前存在着one-to-many的關係,即一個Category對象對應多個Item對象;
3)Category和Item對象之間存在着many-to-many的關係;
4)Category和Item對象之間存在着one-to-one的關係(我認爲這是最少用到的關係類型)。
本文將以Category對象的簡單操作來示例第一種情況。Category對象只有兩個屬性:ID(guid)和Name(string),我們來看看怎麼使用NH來進行Category對象的CRUD操作。
主要內容
1、準備數據庫
2、編寫配置文件
3、編寫POCO類
4、Category對象的CRUD操作
一、準備數據庫
新建數據表,對應於Category對象的屬性,該數據表只有CategoryID和Name兩個字段:
[CategoryID] [uniqueidentifier] NOT NULL ,
[Name] [nvarchar] (50) COLLATE Chinese_PRC_CI_AS NOT NULL
) ON [PRIMARY]
GO
二、編寫配置文件
nh最令我不滿的一點是即使是嘗試一個非常簡單的crud操作,都要先編寫配置文件,而且目前好像也沒有很好的自動生成工具。下面讓我們新建Console工程BasicMappings,編寫nhibernate配置文件和xml mappings文件。
1、新建文件hibernate.cfg.xml,並輸入一下內容:
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.0" >
<session-factory name="CollectionMappings">
<!-- properties -->
<property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
<property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
<property name="connection.connection_string">Server=localhost;database=NHTrial;User Id=sa;Password=sa</property>
<property name="show_sql">false</property>
<property name="dialect">NHibernate.Dialect.MsSql2000Dialect</property>
<property name="use_outer_join">true</property>
</session-factory>
</hibernate-configuration>
同時,因爲hibernate.cfg.xml文件要求在輸出目錄下,還需要在[項目屬性]->[通用屬性]->[生成事件]->[生成後事件命令行]中添加
2、新建objects.hbm.xml文件,並把文件屬性設爲”嵌入資源“。NH將根據*.hbm.xml中的配置進行o/r mapping的操作。
輸入以下內容:
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0">
<!-- mapping for Category -->
<class name="BasicMappings.Category, BasicMappings" table="nh_categories">
<id name="CategoryID" column="CategoryID" type="Guid">
<generator class="guid" />
</id>
<property name="Name" type="string" length="50" />
</class>
</hibernate-mapping>
把NH源文件中包含的nhibernate-mapping-2.0.xsd文件拷貝到%.NET 2003安裝目錄%/Common7/Packages/schemas/xml文件夾下,可獲得intellisense的輸入支持。
1) class節點。該節點指示NH對該類的對象進行orm操作的所需的信息。
class節點的部分重要屬性含義:
Attributes<?XML:NAMESPACE PREFIX = O /> |
Usage |
Example |
name |
指示所映射類的全限定名稱,格式如namespace.className.assemblyName。Required |
BasicMappings.Category, BasicMappings |
table |
指示該類所對應的數據表名稱。Required |
nh_categories |
schema |
指示所使用的數據庫schema,默認繼承hibernate-mappings的schema設定。 |
NhTrial.dbo |
mutable |
指示該類的對象可變,即nh是否可對此對象進行保存和修改的持久化操作。Optional |
|
其他還有lazy, persister和proxy等可選屬性,在後續文章中會有介紹。
2) id節點。id節點設定了該class的主鍵信息:
Attributes |
Usage |
Example |
name |
指示對象的主鍵屬性的名稱 |
ID |
type |
指示該屬性的NH數據類型。可選,NH可自動轉換。 |
Guid |
column |
指示該屬性對應的數據字段名稱,默認取name屬性值。Optional |
ID |
unsaved-value |
指示該對象未保存的主鍵屬性的取值,用於ISession.SaveOrUpdate()操作提供根據。Optional |
|
access |
指示NH對該屬性所採取的access-strategy和naming-strategy。默認從hibernate-mapping的default-access繼承。Optional |
field.camelcase |
3)generator節點。該節點指示了主鍵的生成方式
class |
usage |
identity |
支持DB2/MySql/MsSql/Sybase/HypersonicSql,生成整型自增id |
sequence |
支持DB2/PostgreSql/Oracle,生成整型自增id |
guid |
指示使用Guid.NewGuid來生成主鍵值 |
native |
指示根據數據類型,按照identity、sequence或hilo的方式生成主鍵 |
assigned |
指示主鍵值的設定由用戶代碼完成,NH無需理會 |
4)property節點。該節點指示了NH進行屬性映射所需要的信息:
Attributes |
Usage |
Example |
name |
指示對象的屬性名稱 |
Name |
column |
指示該屬性對應的數據列名稱,默認取name屬性。Optional |
Name |
type |
指示該屬性的NH數據類型。可選,NH可自動轉換 |
String |
update |
指示在進行update時是否保存該屬性的設置。 |
true|false |
insert |
指示在進行save操作時是否保存該屬性的設置。 |
true | false |
formula |
指示該屬性爲表達式,將使column設置失效。 |
ID + Name |
access |
指示NH對該屬性所採取的access-strategy和naming-strategy。默認從hibernate-mapping的default-access繼承。Optional |
field.camelcase |
解釋一下反覆出現access設置,access=access-strategy + . + naming-strategy。
access-trategy的取值包括:
1)Property:默認值,NH在進行orm時將使用已定義的getter和setter來進行該屬性的讀取和設置。
2)field:NH在進行orm時,將使用反射來讀取和設置數據成員。
3)nosetter:使用getter來讀取屬性值,使用反射方式來設置對應的數據成員。
4) ClassName:使用指定的訪問類進行屬性的訪問和設置,ClassName爲該訪問類的全限定名稱。
naming -strategy指示了在映射時,應該對name屬性進行格式轉換的方式。除非access-strategy爲nosetter,naming- strategy爲可選設置,當未設置naming-strategy時,將直接使用name屬性值進行映射。下面以name=FooBar爲例,看看 naming-strategy的轉換後的結果:
naming-strategy |
example |
未設置 |
FooBar |
camelcase |
fooBar |
camelcase-underscore |
_fooBar |
lowercase |
Foobar |
lowercase-underscore |
_foobar |
pascalcase-underscore |
FooBar |
pascalcase-m-underscore |
_FooBar |
|
|
除了上述編寫xml mappings文件的方式外,NHibernateContrib庫中還有通過Attribute的方式來設定orm信息的方式,在後續文章中會有介紹。
三、編寫POCO類
POCO類的說明可參考我之前發的NHibernate學習手記(4) - 持久化類(Persistent class)的設計。
新建類Category.cs,內容如下:
2
3 namespace BasicMappings
4 {
5 /// <summary>
6 /// Category 的摘要說明
7 /// </summary>
8 /// 創 建 人: Aero
9 /// 創建日期: 2006-3-17
10 /// 修 改 人:
11 /// 修改日期:
12 /// 修改內容:
13 /// 版 本:
14 public class Category
15 {
16 private Guid _categoryId;
17
18 private string _name = string.Empty;
19
20 public Guid CategoryID
21 {
22 get { return this._categoryId; }
23 set { this._categoryId = value; }
24 }
25
26 public string Name
27 {
28 get { return this._name; }
29 set { this._name = value; }
30 }
31
32 #region 構造函數
33 /// <summary>
34 /// 默認無參構造函數
35 /// </summary>
36 /// 創 建 人: Aero
37 /// 創建日期: 2006-3-17
38 /// 修 改 人:
39 /// 修改日期:
40 /// 修改內容:
41 public Category()
42 {
43
44 }
45
46 #endregion
47 }
48 }
49
四、Category對象的CRUD操作
本文將演示如何保存隨機生成的Category對象,和如何實現對象的查詢。簡單的CRUD操作可參考NHibernate學習手記(1) - 對象的簡單CRUD操作 。新建文件Programm.cs:
1、保存Category對象
2
3 static ISessionFactory Factory
4 {
5 get { return Programm._factory; }
6 }
7
8 /// <summary>
9 /// initializing
10 /// </summary>
11 static Programm()
12 {
13 Configuration cfg = new Configuration().Configure();
14 cfg.AddAssembly("BasicMappings");
15
16 // initialize factory
17 Programm._factory = cfg.BuildSessionFactory();
18 }
19
20 /// <summary>
21 /// save transient object
22 /// </summary>
23 /// <param name="persistentObj"></param>
24 static void Save(object persistentObj)
25 {
26 using (ISession session = Programm.Factory.OpenSession())
27 {
28 ITransaction trans = session.BeginTransaction();
29
30 try
31 {
32 session.Save(persistentObj);
33 trans.Commit();
34 }
35 catch
36 {
37 trans.Rollback();
38 throw;
39 }
40 }
41 }
1)line13-18,初始化Configuration和SessionFactory。line13中的
A、通過Configuration.AddAssembly(assemblyName),nh將自動查找所制定程序集中的所有*.hbm.xml嵌入文件獲取o/r mapping信息
B、通過Configuration.AddType(Type t),nh將自動查找當前程序集中名爲typeName.hbm.xml的嵌入文件該類的o/r mapping信息
C、通過Configuration.AddXmlFile(fileName),nh將自動查找當前程序集中名爲fileName的嵌入文件,獲取o/r mapping信息
2)line24-41,保存對象。NH中進行對象的save/update/delete操作時都必須打開事務,推薦使用using的方式來使用ISession對象。
2、查詢全部對象
2 /// list all category objects in the repository
3 /// </summary>
4 static void ListCategory()
5 {
6 using (ISession session = Programm.Factory.OpenSession())
7 {
8 IList categories = session.CreateCriteria(typeof(Category)).List();
9
10 foreach (Category category in categories)
11 {
12 Console.WriteLine(category.CategoryID + " " + category.Name);
13 }
14 }
15 }
3、刪除全部對象
作爲一種好習慣,我們在示例代碼的開始前和結束後都應該清空所添加的臨時數據:)
2 /// remove all category objects from the repository
3 /// </summary>
4 static void Clear()
5 {
6 using (ISession session = Programm.Factory.OpenSession())
7 {
8 ITransaction trans = session.BeginTransaction();
9
10 try
11 {
12 session.Delete("from Category");
13 trans.Commit();
14 }
15 catch
16 {
17 trans.Rollback();
18 throw;
19 }
20 }
21 }
在刪除所有Category對象時,我們用了一小段HQL代碼“from Category”,在後續的文章裏會有介紹。
完整的代碼可從下載:ObjectsMapping.rar,其中的ExtendedCategory示例了更多的ISession的操作。