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 databaseISession 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的欲望?希望和大家一起交流,共同进步。

优质内容筛选与推荐>>
1、oracle数据链接
2、Excel 2010中,“数据挖掘”控件安装后不显示问题的解决方案
3、JavaScript之八皇后问题(递归)
4、jQuery ajax 路由和过滤器
5、怎么去除google的“该网站可能含有恶意软件,有可能会危害您的电脑。


长按二维码向我转账

受苹果公司新规定影响,微信 iOS 版的赞赏功能被关闭,可通过二维码转账支持公众号。

    阅读
    好看
    已推荐到看一看
    你的朋友可以在“发现”-“看一看”看到你认为好看的文章。
    已取消,“好看”想法已同步删除
    已推荐到看一看 和朋友分享想法
    最多200字,当前共 发送

    已发送

    朋友将在看一看看到

    确定
    分享你的想法...
    取消

    分享想法到看一看

    确定
    最多200字,当前共

    发送中

    网络异常,请稍后重试

    微信扫一扫
    关注该公众号