你是否正在爲編寫和維護冗長和複雜的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的慾望?希望和大家一起交流,共同進步。