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 | 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的操作。