你是否正在为编写和维护冗长和复杂的SQL语句而苦恼?
你是否厌倦了继续以面向过程的开发方式,而想开始尝试以面向对象的方式去思考?
你是否想跳出重复编写SQL语句的囹囵,而想更加专注于实现用户需求的逻辑实现?
...
和许多开发人员一样,我非常反感(甚至是恐惧)sql语句,这种当初设计用来和数据库进行会话的语言,想不到现在被发扬光大到可以用来编写业务逻辑(通过任意复杂的组合)。但我们完全可以以对象的方式来思考数据库编程,通过采用ORM(Object-Relation Mapping),把我们从繁杂的Sql语句编写工作中解脱出来,从而引导我们以对象的方式进行开发。
于是我最近打算学习NHibernate(简称NH),并将陆续在blog上发表学习的总结,希望能够和各位多多交流。
主要内容
1、事先的准备工作
2、编写帖子(Post)的实体类
3、编写NH所需要的配置文件
4、使用NH进行对象的CRUD操作
5、浅谈Rich Domain Model
一、准备工作
首先,我们在数据库NHTrial中新建一数据表nh_posts,用于存储帖子数据
CREATE TABLE [dbo].[nh_posts] ( [PostID] [uniqueidentifier] NOT NULL , [Title] [varchar] (
255
) COLLATE Chinese_PRC_CI_AS NOT NULL , [Content] [text] COLLATE Chinese_PRC_CI_AS NOT NULL , [Creator] [varchar] (
50
) COLLATE Chinese_PRC_CI_AS NOT NULL , [CreateDate] [datetime] NOT NULL , [LastUpdateDate] [datetime] NULL , [LastUpdator] [varchar] (
50
) COLLATE Chinese_PRC_CI_AS NULL ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
二、编写Post实体类
新建工程NHClass,添加类Post.cs,并编写代码如下:
using
System;
using
System.Collections;
namespace
NHClass {
///
///
Post 贴子类
///
///
创 建 人: Aero
///
创建日期: 2006-3-9
///
修 改 人:
///
修改日期:
///
修改内容:
///
版 本:
public
class
Post {
#region
数据成员定义
private
Guid postId;
private
string
title;
private
string
content;
private
string
creator;
private
DateTime createDate
=
System.DateTime.Now;
private
string
lastUpdator;
private
DateTime lastUpdateDate
=
System.DateTime.Now;
#endregion
#region
属性定义
public
Guid PostID {
get
{
return
this
.postId; }
set
{
this
.postId
=
value; } }
public
string
Title {
get
{
return
this
.title; }
set
{
this
.title
=
value; } }
public
string
Content {
get
{
return
this
.content; }
set
{
this
.content
=
value; } }
public
string
Creator {
get
{
return
this
.creator; }
set
{
this
.creator
=
value; } }
public
DateTime CreateDate {
get
{
return
this
.createDate; }
set
{
this
.createDate
=
value; } }
public
string
LastUpdator {
get
{
return
this
.lastUpdator; }
set
{
this
.lastUpdator
=
value; } }
public
DateTime LastUpdateDate {
get
{
return
this
.lastUpdateDate; }
set
{
this
.lastUpdateDate
=
value; } }
#endregion
#region
构造函数
///
///
默认无参构造函数
///
///
创 建 人: Aero
///
创建日期: 2006-3-9
///
修 改 人:
///
修改日期:
///
修改内容:
public
Post() {
//
//
TODO: 在此处添加构造函数逻辑
//
}
#endregion
} }
NH通过O/R Mapping,把关系数据映射为实体对象(字段映射为实体的属性),让我们在开发只需直接操纵对象。
三、编写NHibernate需要的配置文件
NH实现O/R Mapping当然不是通过某种神奇的方式,需要我们编写配置文件来告诉它该如何进行对象映射,并且已哪种方式来运行NH,需要映射的是什么类型的数据库等。
1、编写用于O/R Mapping的配置文件。
NHibernate提供多种编写配置文件的方式,本文只讨论最简单的方式,即为每一个实体类编写一个配置文件。在工程NHClass中新建文件Post.hbm.xml,把该文件的属性设为"嵌入资源",并输入以下内容:
<xml version="1.0" encoding="utf-8" ?> <hibernate-mapping xmlns="urn:nhibernate-mapping-2.0"> <class name="NHClass.Post, NHClass" table="nh_posts"> <id name="PostID" column="PostID" type="Guid"> <generator class="assigned" /> id> <property name="Title" column="Title" type="String" length="255"/> <property name="Content" column="Content" type="String" /> <property name="Creator" column="Creator" type="String" length="50"/> <property name="CreateDate" column="CreateDate" type="DateTime"/> <property name="LastUpdator" column="LastUpdator" type="String" length="50"/> <property name="LastUpdateDate" column="LastUpdateDate" type="DateTime"/> </class> </hibernate-mapping>
下面简单说明一下该配置文件:
1)class: name属性指示了Post实体类的类名和所在的Assebmly的名称,NH将通过反射的方式找到所指示的实体类,关于.Net的反射的说明,请参考MSDN; table属性指示了该实体所对应的数据表的表名
2)property: 指示实体属性和数据列的如何映射。name为实体的属性名称,实体的该属性可以为public/private/protected,甚至是internal;column指示了该属性对应的数据列,若实体属性名称和数据列名称相同(忽视大小写),可以省略;type指示了实体属性的.Net数据类型,可以省略,NH可以自动转换;length只是对string类型的属性适用,指示了字符串的最大长度。
3)id: 指示主键。NH支持自动生成主键、数据库生成主键和手工赋值三种方式,我们这里手工赋值的方式,设定generator的class="assigned"。
2、修改app.config或web.config配置NHibernate的属性。
在app.config或web.config文件中添加以下内容:
<
configSections
>
<
section name
=
"
nhibernate
"
type
=
"
System.Configuration.NameValueSectionHandler, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
"
/>
configSections> <nhibernate> <add key="hibernate.connection.provider" value="NHibernate.Connection.DriverConnectionProvider" /> <add key="hibernate.dialect" value="NHibernate.Dialect.MsSql2000Dialect" /> <add key="hibernate.connection.driver_class" value="NHibernate.Driver.SqlClientDriver" /> <add key="hibernate.connection.connection_string" value="Server=localhost;uid=sa;password=sa;database=NHTrial" /> nhibernate>
该配置信息指定了NH的运行时、所使用的数据库驱动程序和数据库连接字符串等信息,也可在运行的时候赋值。
四、使用NHibernate进行对象的CRUD操作
相信大家都迫不及待了把,现在让我们看看如何使用NH进行简单的CRUD。请注意本文的用词,我们讨论的是对象的操作,不是过程化的sql调用!
1、添加Post对象
void
AddPost() {
//
initialize the configuration
Configuration cfg
=
new
Configuration(); cfg.AddAssembly(
"
NHClass
"
);
ISessionFactory factory = cfg.BuildSessionFactory();
//
start a session with the database
//
the ISession object represents a connection to your backend database
ISession session = factory.OpenSession();
//
the ITransaction object represents a NH Managed transaction
//
always start a transaction before u want to do something on the backend database
ITransaction trans
=
session.BeginTransaction();
//
initialize ur Post
Post post
=
new
Post(); post.PostID
=
Guid.NewGuid(); post.Title
=
"
hello Nibernate
"
; post.Content
=
"
foo test
"
; post.Creator
=
"
foo
"
; post.LastUpdator
=
"
bar
"
; post.CreateDate
=
System.DateTime.Now.Date; post.LastUpdateDate
=
System.DateTime.Now.Date;
//
store the new post
session.Save(post);
//
commit the transaction
trans.Commit();
//
end the session
session.Close(); }
没错,就是那么简单!打开和数据库的会话,保存对象,最后关闭会话,一切都那么自然。美中不足的是其中的cfg.AddAssembly("NHClass")表示注册Post类所在的程序集,感觉很不优雅。
其他的操作都要用到ISessionFactory,为了便于描述,我们先进行一次简单的重构,Extract Method:
ISessionFactory _factory; ISessionFactory Factory {
get
{
if
(_factory
==
null
) {
//
initialize the configuration
Configuration cfg
=
new
Configuration(); cfg.AddAssembly(
"
NHClass
"
);
//
create a session object
//
the ISession object represents a connection to your backend database
_factory
=
cfg.BuildSessionFactory();
}
return _factory; } }
void
AddPost() {
//
start a session with the database
//
the ISession object represents a connection to your backend database
ISession session
=
this.Factory.OpenSession();
//
the ITransaction object represents a NH Managed transaction
//
always start a transaction before u want to do something on the backend database
ITransaction trans
=
session.BeginTransaction();
//
initialize ur Post
Post post
=
new
Post(); post.PostID
=
Guid.NewGuid(); post.Title
=
"
hello Nibernate
"
; post.Content
=
"
foo test
"
; post.Creator
=
"
foo
"
; post.LastUpdator
=
"
bar
"
; post.CreateDate
=
System.DateTime.Now.Date; post.LastUpdateDate
=
System.DateTime.Now.Date;
//
store the new post
session.Save(post);
//
commit the transaction
trans.Commit();
//
end the session
session.Close(); }
2、查询帖子
先看看怎么查询全部的帖子
void
ListAllPost() { Console.WriteLine(
"
list all post in table nh_posts
"
);
//
start a session
ISession session
=
this
.Factory.OpenSession(); IList posts
=
session.CreateCriteria(
typeof
(Post)).List();
foreach
(Post post
in
posts) { Console.WriteLine(post.PostID.ToString()
+
"
:
"
+
post.Title); } session.Close(); }
再看看怎么查询指定PostID的帖子
void
ListPostById(Guid postId) { Console.WriteLine(
"
list posts of the given id
"
); IList posts
=
null
;
//
start a data session
ISession session
=
this
.Factory.OpenSession();
//
get post of the given post id
posts
=
session.CreateCriteria(
typeof
(Post)) .Add(Expression.Eq(
"
PostID
"
, postId)).List();
//
close a session to the backend database
session.Close();
foreach
(Post post
in
posts) { Console.WriteLine(post.PostID.ToString()
+
"
:
"
+
post.Title); } }
查询所有标题包含关键字的帖子对象,并以LastUpdateDate降序排列
void
ListPostByTitle(
string
keyword) { Console.WriteLine(
"
list posts that contains the given keyword in their title, sorted by last update date
"
); IList posts
=
null
;
//
start a data session
ISession session
=
this.Factory.OpenSession(); keyword
=
string
.Format(
"
%{0}%
"
, keyword);
//
retrieve all posts in the database that contains the given keyword
posts
=
session.CreateCriteria(
typeof
(Post)) .Add(Expression.Like(
"
Title
"
, keyword)) .AddOrder(
new
Order(
"
LastUpdateDate
"
,
false
)) .List();
//
close a session to the backend database
session.Close();
foreach
(Post post
in
posts) { Console.WriteLine(post.PostID.ToString()
+
"
:
"
+
post.Title); } }
NHibernate.Expression命名空间中封装了丰富的算符,如下表所示。
同时,NHibrenate还支持Query By Example(QBE)的查询方式,使得对象查询实现起来简直是太简单了!
3、更新Post对象
void
UpdatePost(Post post) { ISession session
=
this
.Factory.OpenSession(); Console.WriteLine(
"
original Post title is :
"
+
post.Title);
//
modify post title
post.Title
=
"
new title
"
+
Guid.NewGuid().ToString(); session.Update(post, post.PostID);
//
retrieve updated post from database
Post updatedPost
=
session.Load(
typeof
(Post), postId)
as
Post; Console.WriteLine(
"
updated Post title is :
"
+
post.Title); session.Close(); }
4、删除指定的post对象
void
Delete(Post post) {
//
start a data session
ISession session
=
this
.Factory.OpenSession();
//
always start a transaction when handling the insert/update/delete operation
ITransaction trans
=
session.BeginTransaction();
//
delete current post record from to the backend database
session.Delete(post);
//
commit a transaction
trans.Commit();
//
close a session to the backend database
session.Close(); }
对于使用NHibernate进行对象的CRUD操作,本文就介绍到这里,是否已经激起各位一起学习NHibernate的欲望?希望和大家一起交流,共同进步。