nh的online document中讨论了三种情况的的o/r mapping:
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两个字段:
code highlighting produced by actipro codehighlighter (freeware)
http://www.codehighlighter.com/
-->create table [dbo].[nh_categories] (
[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,并输入一下内容:
code highlighting produced by actipro codehighlighter (freeware)
http://www.codehighlighter.com/
-->
<?xml version="1.0" encoding="utf-8" ?><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文件要求在输出目录下,还需要在[项目属性]->[通用属性]->[生成事件]->[生成后事件命令行]中添加
code highlighting produced by actipro codehighlighter (freeware)
http://www.codehighlighter.com/
-->copy $(projectdir)/hibernate.cfg.xml $(targetdir)
2、新建objects.hbm.xml文件,并把文件属性设为”嵌入资源“。nh将根据*.hbm.xml中的配置进行o/r mapping的操作。
输入以下内容:
code highlighting produced by actipro codehighlighter (freeware)
http://www.codehighlighter.com/
-->
<?xml version="1.0" encoding="utf-8" ?><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>
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 |
poco类的说明可参考我之前发的nhibernate学习手记(4) - 持久化类(persistent class)的设计。
新建类category.cs,内容如下:
1 using system; 2 3 namespace basicmappings 4 ...{ 5 /**//// <summary> 6 /**//// category 的摘要说明 7 /**//// </summary> 8 /**//// 创 建 人: aero 9 /**//// 创建日期: 2006-3-1710 /**//// 修 改 人: 11 /**//// 修改日期:12 /**//// 修改内容:13 /**//// 版 本:14 public class category15 ...{16 private guid _categoryid;1718 private string _name = string.empty;1920 public guid categoryid21 ...{22 get ...{ return this._categoryid; }23 set ...{ this._categoryid = value; }24 }2526 public string name27 ...{28 get ...{ return this._name; }29 set ...{ this._name = value; }30 }3132 构造函数#region 构造函数33 /**//// <summary>34 /**//// 默认无参构造函数35 /**//// </summary>36 /**//// 创 建 人: aero37 /**//// 创建日期: 2006-3-1738 /**//// 修 改 人: 39 /**//// 修改日期:40 /**//// 修改内容:41 public category()42 ...{4344 }4546 #endregion47 }48 }49
本文将演示如何保存随机生成的category对象,和如何实现对象的查询。简单的crud操作可参考nhibernate学习手记(1) - 对象的简单crud操作 。新建文件programm.cs:
1、保存category对象
1 static readonly isessionfactory _factory; 2 3 static isessionfactory factory 4 ...{ 5 get ...{ return programm._factory; } 6 } 7 8 /**//// <summary> 9 /**//// initializing10 /**//// </summary>11 static programm()12 ...{13 configuration cfg = new configuration().configure();14 cfg.addassembly("basicmappings");1516 // initialize factory17 programm._factory = cfg.buildsessionfactory();18 }1920 /**//// <summary>21 /**//// save transient object22 /**//// </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();2930 try31 ...{32 session.save(persistentobj);33 trans.commit();34 }35 catch36 ...{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、查询全部对象
1 /**//// <summary> 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(); 910 foreach (category category in categories)11 ...{12 console.writeline(category.categoryid + " " + category.name);13 }14 }15 }3、删除全部对象作为一种好习惯,我们在示例代码的开始前和结束后都应该清空所添加的临时数据:) 1 /**//// <summary> 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(); 910 try11 ...{12 session.delete("from category");13 trans.commit();14 }15 catch16 ...{17 trans.rollback();18 throw;19 }20 }21 }
在删除所有category对象时,我们用了一小段hql代码“from category”。
闽公网安备 35060202000074号