NHibernate学习手记(1) - 对象的简单CRUD操作

你是否正在为编写和维护冗长和复杂的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的欲望?希望和大家一起交流,共同进步。

posted @ 2008-08-21 23:34  永不放弃-Jack wu  阅读(356)  评论(0编辑  收藏  举报