NHibernate 使用配置与实现简单查询

NHibernate是从Hibernate迁移到DotNet来的优秀的ORM框架,它把数据库中的表的关系模型转换为程序中的对象之间的关联模型,从而使程序模型更接近于现实中的逻辑。作为DotNet本身在VS2008 SP1中新增了ADO.NET Entity Framework,但EF非常庞大,远超过ORM的概念范畴,使初学者难以把握。而在VS2005中却没有这种ORM框架,在此我们先以NHibernate为工具研究ORM思想,并研究它如何在VS2005中应用。
ORM就是“对象-映射-关系”的简称,它主要包含三部分:
    关系:关系型数据库。
    对象:实体对象类
    映射:XML文件,指定实体类与表的对应关系。

在这里需要我们操作的就有两点:编写实体对象类,配置映射文件。这两部份一般不需要我们手动编写,我们可以使用CodeSmith的模板来生成。

一、R-关系部份
以下面的数据库为例:
create database mydb
go
use mydb
go
--水果表
create table Fruit
(
Ids varchar(50) primary key,
[Name] varchar(50) not null,
Price decimal(8,2),
Source varchar(50),
Stack varchar(50),
Numbers int, --库存数量
[Image] varchar(50)
)
go
insert into fruit values('k001','苹果',2.4,'烟台','2',100,'image/0.gif')
insert into fruit values('k002','菠萝',1.4,'广东','3',100,'image/1.gif')
insert into fruit values('k003','桔子',2.4,'福州','3',100,'image/2.gif')
insert into fruit values('k004','葡萄',2.4,'新缰','2',100,'image/3.gif')
insert into fruit values('k005','樱桃',2.4,'青岛','4',100,'image/4.gif')
insert into fruit values('k006','桃子',2.4,'花果山','5',100,'image/5.gif')
insert into fruit values('k007','香蕉',2.4,'济南','5',100,'image/6.gif')

Fruit表是一个独立的单一表,我们以此表为例,研究如何配置ORM框架,并实现增、删、改、查功能

二、O-对象部份
第一步:新建一个类库Common
第二步:向Common项目中添加NHibernate.dll引用
第三步:使用CodeSmith执行NHibernate.cst文件生成实体类和映射文件
《图1》
Fruit.cs的文件代码如下:
using System;
using System.Collections;
using System.Web.UI.WebControls;

使用配置与实现简单查询" alt="一、NHibernate 使用配置与实现简单查询" src="http://hiphotos.baidu.com/grayworm/pic/item/3be3a1f8273c4211d8f9fd52.jpg" border=0 real_src="http://hiphotos.baidu.com/grayworm/pic/item/3be3a1f8273c4211d8f9fd52.jpg" SMALL="0">

 

namespace Common
{

public class Fruit : System.IComparable
{
     //成员变量
   protected string _id;
   protected string _name;
   protected decimal _price;
   protected string _source;
   protected string _stack;
   protected int _numbers;
   protected string _image;
   protected static String _sortexpression_r = "Id";
   protected static SortDirection _sortDirection = SortDirection.Ascending;

        //构造函数
   public Fruit() { }

   public Fruit( string name, decimal price, string source, string stack, int numbers, string image )
   {
    this._name = name;
    this._price = price;
    this._source = source;
    this._stack = stack;
    this._numbers = numbers;
    this._image = image;
   }
  
   //属性
   public virtual string Id
   {
    get {return _id;}
    set
    {
     if ( value != null && value.Length > 50)
      throw new ArgumentOutOfRangeException("Invalid value for Id", value, value.ToString());
     _id = value;
    }
   }

   public virtual string Name
   {
    get { return _name; }
    set
    {
     if ( value != null && value.Length > 50)
      throw new ArgumentOutOfRangeException("Invalid value for Name", value, value.ToString());
     _name = value;
    }
   }

   public virtual decimal Price
   {
    get { return _price; }
    set { _price = value; }
   }

   public virtual string Source
   {
    get { return _source; }
    set
    {
     if ( value != null && value.Length > 50)
      throw new ArgumentOutOfRangeException("Invalid value for Source", value, value.ToString());
     _source = value;
    }
   }

   public virtual string Stack
   {
    get { return _stack; }
    set
    {
     if ( value != null && value.Length > 50)
      throw new ArgumentOutOfRangeException("Invalid value for Stack", value, value.ToString());
     _stack = value;
    }
   }

   public virtual int Numbers
   {
    get { return _numbers; }
    set { _numbers = value; }
   }

   public virtual string Image
   {
    get { return _image; }
    set
    {
     if ( value != null && value.Length > 50)
      throw new ArgumentOutOfRangeException("Invalid value for Image", value, value.ToString());
     _image = value;
    }
   }

        public static String Sortexpression_r
        {
            get { return _sortexpression_r; }
            set { _sortexpression_r = value; }
        }

        public static SortDirection SortDirection
        {
            get { return _sortDirection; }
            set { _sortDirection = value; }
        }
  
        //实现IComparable接口的排序方法
        public virtual int CompareTo(object obj)
        {
    if (!(obj is Fruit))
     throw new InvalidCastException("This object is not of type Fruit");
   
    int relativue;
    switch (Sortexpression_r)
    {
     case "Id":
      relativue = this.Id.CompareTo(((Fruit)obj).Id);
      break;
     case "Name":
      relativue = this.Name.CompareTo(((Fruit)obj).Name);
      break;
     case "Price":
      relativue = (this.Price != null) ? this.Price.CompareTo(((Fruit)obj).Price) : -1;
      break;
     case "Source":
      relativue = (this.Source != null) ? this.Source.CompareTo(((Fruit)obj).Source) : -1;
      break;
     case "Stack":
      relativue = (this.Stack != null) ? this.Stack.CompareTo(((Fruit)obj).Stack) : -1;
      break;
     case "Numbers":
      relativue = (this.Numbers != null) ? this.Numbers.CompareTo(((Fruit)obj).Numbers) : -1;
      break;
     case "Image":
      relativue = (this.Image != null) ? this.Image.CompareTo(((Fruit)obj).Image) : -1;
      break;
                default:
                    goto case "Id";
    }
            if (Fruit.SortDirection == SortDirection.Ascending)
     relativue *= -1;
    return relativue;
   }
}
}

三、M-映射部分
Fruit.hbm.xml映射文件如下(在这里我用的是nhibernate2.2):
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
    <!--Common.Fruit类与Fruit表进行映射-->
<class name="Common.Fruit, Common" table="Fruit">
     <!--主键Id映射到Ids列-->
   <id name="Id" type="String" unsaved-value="null">
    <column name="Ids" length="50" sql-type="varchar" not-null="true" unique="true" index="PK__Fruit__7C8480AE"/>
   <generator class="native" />
   </id>
   <!--列映射-->
   <property name="Name" type="String">
    <column name="Name" length="50" sql-type="varchar" not-null="true"/>
   </property>
   <property name="Price" type="Decimal">
    <column name="Price" length="5" sql-type="decimal" not-null="false"/>
   </property>
   <property name="Source" type="String">
    <column name="Source" length="50" sql-type="varchar" not-null="false"/>
   </property>
   <property name="Stack" type="String">
    <column name="Stack" length="50" sql-type="varchar" not-null="false"/>
   </property>
   <property name="Numbers" type="Int32">
    <column name="Numbers" length="4" sql-type="int" not-null="false"/>
   </property>
   <property name="Image" type="String">
    <column name="Image" length="50" sql-type="varchar" not-null="false"/>
   </property>
</class>
</hibernate-mapping>
第四步:把Fruit.hbm.xml文件作为嵌入资源,否则找不到该文件,就无法识别我们的实体对象类。

到此为至,我们的O、R、M三部份都实现完成了,下面的内容就是配置NHibernate引擎。
第五步:编写hibernate.cfg.xml配置文件,并把该文件入在网站的BIN文件夹中,否则也会找不到该文件。

四、NHibernate的配置部份
<?xml version="1.0" encoding="utf-8"?>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2" >
    <session-factory>
        <property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
        <property name="connection.connection_string">
            server=.;database=mydb;uid=sa;pwd=123;
        </property>
        <property name="adonet.batch_size">10</property>
        <property name="show_sql">true</property>
        <property name="dialect">NHibernate.Dialect.MsSql2005Dialect</property>
        <property name="use_outer_join">true</property>
        <property name="command_timeout">10</property>
        <property name="query.substitutions">true 1, false 0, yes 'Y', no 'N'</property>
        <mapping assembly="Common"/>
    </session-factory>
</hibernate-configuration>
hibernate.cfg.xml中配置了NHibernate的数据库链接,Sql方言相关信息。

到目前为止所有的配置信息都已完成,剩下的内容就是编写代码访问数据库了。
NHibernate访问数据库常用的有两个接口:ISessionFactory和ISession。
ISessionFactory接口:负责初始化NHibernate。它充当数据存储源的代理,并负责创建Session对象。这里用到了工厂模式。一般情况下,一个项目通常只需要一个SessionFactory就够,当需要操作多个数据库时,可以为每个数据库指定一个SessionFactory。
Session接口:负责执行被持久化对象的CRUD操作(增、删、改、查)。但ISession是非线程安全的。NHibernate的ISession不同于HTTP应用中的HttpSession,我们将HttpSesion对象称为用户session。

五、使用NHibernate访问数据库
第六步:在Common项目中建立SessionManager类
using System;
using System.Collections.Generic;
using System.Text;
using NHibernate;
using NHibernate.Cfg;
namespace Common
{
    public class SessionManager
    {
        private ISessionFactory _SessionFactory;
        private ISession _Session;
        public SessionManager()
        {
            //生成SessionFactory
            _SessionFactory = new Configuration().Configure().BuildSessionFactory();
            //使用SessionFactory对象生成Session对象
            _Session = _SessionFactory.OpenSession();
        }
        //返回Session对象
        public ISession Session
        {
            get
            {
                return _Session;
            }
        }
    }
}
该类的作用就是生成Session对象,以便对数据库的操作。

第七步:创建数据库访问代码
using System;
using System.Collections.Generic;
using System.Text;
using NHibernate;

namespace Common
{
    public class FruitDA
    {
        private ISession _Session;
        public FruitDA()
        {
            //生成ISession对象
            _Session = new SessionManager().Session;
        }
        public IList<Fruit> Select()
        {
            //使用ISession对象的CreateQuery()方法来执行HQL查询数据库,并返回泛型集合数据
            IList<Fruit> list = _Session.CreateQuery("from Fruit").List<Fruit>();
            return list;
        }
    }
}

第八步:页面调用FruitDA类的Select()方法查询数据,并显示在页面上
GridView1.DataSource = new FruitDA().Select();
GridView1.DataBind();

好了,使用NHibernate建立一个简单查询就完成了。

NHibernate与ADO.NET访问数据库
NHibernate只需要我们编写好实体类和映射文件就可以了,当然这部份代码我们可以使用CodeSmith来生成,一旦配置好NHibernate后,所以的数据库访问都由NHibernate代我们完成。作为开发人员,我们只需要理清商业逻辑,管理好我们的实体对象就可以了,不用再使用SqlConnection,SqlCommand等对象去为每个表编写枯燥数据库操作类了。

NHibernate与Linq To Sql
从易用性上来讲,NHibernate确实不如Linq To Sql容易使用,在实体类的生成和映射文件的生成中Linq To Sql只需要点点鼠标就可以实现了。但Linq To Sql是在VS2008中提供出来的,在VS2005中无法使用的。另外,对数据量不太大的情况下,Linq To Sql的性能不如NHibernate高,在数据量大的情况下,Linq To Sql则表现出强悍的性能。另外Linq To Sql目前只适用于SqlServer数据库,还不能算是一个完善的ORM框架。

posted @ 2010-04-12 12:59  你妹的sb  阅读(502)  评论(0编辑  收藏  举报
百度一下