分享

NHibernate Step by Step

 mefly 2007-12-28
lisirui





级别: 新手上路
精华: 0
发帖: 12
威望: 13 点
金钱: 120 RMB
注册时间:2007-09-01
查看作者资料 发送短消息 发送邮件 推荐此帖 引用回复这个帖子



NHibernate Step by Step (一) Hello,NHibernate!

好了,今天我们正式开始NHibernate的历程,在第一次的练习中,我将尽量详细地讲解环境的配置,以后将不再详细解释。

基本的软件环境如下:
1.NHibernate
www. 当前版本是1.0.2
2.Code Smith
http://www./
3.NHibernate模板 点击这里下载
当然,少不了VS2005跟SQLServer了,我这里用的是SQLServer2005,教程用在SQLServer2000上应该没有问题,默认情况下,我将建立并使用一个叫NHibernate的数据库。

首先,我们先建立一个最简单的Person表,如下完整脚本(你可以进行修改以适合自己的数据库):

CODE:

USE [NHibernate]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[Person](
  [id] [int] IDENTITY(1,1) NOT NULL,
  [name] [varchar](50) COLLATE Chinese_PRC_CI_AS NOT NULL,
CONSTRAINT [PK_Person] PRIMARY KEY CLUSTERED
(
  [id] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]

GO
SET ANSI_PADDING OFF



仅有两个字段,一个自动增长的id,一个name,如下:


然后将下载的nhibernate-template解压,打开Code Smith,将模板加入”Template Explorer”,如下:


然后在其中的NHibernate.cst上点右键,选择“Execute”,弹出设置窗口,在左边的属性窗口进行如下设置:


注意:SourceDatabase属性在第一次选择时需要配置一个连接字符串,配置好后Code Smith将记录下来。 Assembly属性代表的是生成文件的默认Assembly名,而NameSpace,顾名思义,就是使用的命名空间了,这里我们全部使用”Test.Model”,请记住这个名字,点击左下角的Generate,将会在指定的输出目录下产生两个文件:Person.cs,Person.hbm.xml。

好了,NHibernate需要的类文件和映射文件生成完了,我们可以开始干活了!(生成NHibernate文件均是如此步骤,以后不再赘述)

新建立一个类库工程,为了简洁起见,我们命名为Model,需要注意的是,为了跟刚才生成的文件对应,我们需要在Model工程的属性页中将起Assembly名字设为上面的“Test.Model”,如下:



然后将刚才生成的两个文件Person.cs和Person.hbm.xml加入到Model工程中来,选中Person.hbm.xml文件,在属性窗口中将其“Build Action”设置为“Embedded Resource”(这是非常重要的一步,否则NHibernate将无法找到映射文件),如下:


build,ok,通过。

然后建立一个控制台工程,命名为Console1,添加NHibernate和上面Model项目的引用,另外添加一个应用程序配置文件,如下:
CODE:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<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.connection.driver_class" value="NHibernate.Driver.SqlClientDriver" />
  <add key="hibernate.connection.connection_string" value="Server=localhost;Initial Catalog=NHibernate;Integrated Security=SSPI" />
  <add key="hibernate.connection.isolation" value="ReadCommitted"/>
  <add key="hibernate.dialect" value="NHibernate.Dialect.MsSql2000Dialect" />
</nhibernate>

</configuration>


然后编写如下代码:
CODE:

using System;
using System.Collections.Generic;
using System.Text;
using NHibernate;
using NHibernate.Cfg;
using Test.Model;

namespace Console1
{
  class Program
  {
    static void Main(string[] args)
    {
        Configuration config = new Configuration().AddAssembly("Test.Model");
        ISessionFactory factory = config.BuildSessionFactory();
        ISession session = factory.OpenSession();

        Person person = new Person();
        person.Name = "Jackie Chan";

        ITransaction trans = session.BeginTransaction();
        try
        {
          session.Save(person);
          trans.Commit();
          Console.WriteLine("Insert Success!");
        }
        catch (Exception ex)
        {
          trans.Rollback();
          Console.WriteLine(ex.Message);
        }
    }
  }
}


运行,ok,执行成功!!
我们到数据库检查一下,如下:


我们想要添加的记录已经成功加入到数据库中!!
是不是感觉有些神奇啊?好,我们开始详细解释。
先来看生成的两个文件,第一个是Person.cs,如下:
CODE:
using System;
using System.Collections;

namespace Test.Model
{
  Person#region Person

  /**//// <summary>
  /// Person object for NHibernate mapped table 'Person'.
  /// </summary>
  public class Person
  {
    Member Variables#region Member Variables
   
    protected int _id;
    protected string _name;

    #endregion

    Constructors#region Constructors

    public Person() { }

    public Person( string name )
    {
        this._name = name;
    }

    #endregion

    Public Properties#region Public Properties

    public int Id
    {
        get {return _id;}
        set {_id = value;}
    }

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

   

    #endregion
  }
  #endregion
}



你可以发现,这完全是一个普通的poco类(Plain Old CLR Object),仅仅是对数据库person表的一个完全映射,不依赖于任何框架,可以用来作为持久化类,你可以在任何地方使用而不用担心依赖于某些神秘的运行时东西。

另外,NHibernate需要知道怎样去加载(load)和存储(store)持久化类的对象。这正是NHibernate映射文件发挥作用的地方。映射文件告诉NHibernate它应该访问数据库(database)里面的哪个表(table)及应该使用表里面的哪些字段(column),这就是我们今天要讲的重点了,Person.hbm.xml,如下:
CODE:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0">
<class name="Test.Model.Person, Test.Model" table="Person">
<id name="Id" type="Int32" unsaved-value="0">
  <column name="id" sql-type="int" not-null="true" unique="true" index="PK_Person"/>
  <generator class="native" />
</id>
<property name="Name" type="String">
  <column name="name" length="50" sql-type="varchar" not-null="true"/>
</property>
</class>
</hibernate-mapping>


不用说,最顶层的hibernate-mapping节点是NHibernate用来进行映射的根了,其中,包含一个class节点,里面的name属性对应我们的Person类,注意,需要完整的限定名;而table属性,则显而易见是对应数据库中的Person表了。
我们再往里面看,分别有两个节点,一个是id,对应数据库中的id,一个是属性name,对应表中的column name和Person类中的name属性,整个映射文件简捷明了,一看即知。实际上这是由代码产生工具产生的映射文件,里面很多东西我们其实可以省略,如下写法:
<property name=”Name” column=”name” />
NHibernate将自动去匹配数据库中的列而不需要我们来设置。

下面,我们来看一下应用程序配置文件中都记录了那些东西,如下:
hibernate.connection.provider_class
定制IConnectionProvider的类型.
例如:full.classname.of.ConnectionProvider (如果提供者创建在NHibernate中), 或者 full.classname.of.ConnectionProvider, assembly (如果使用一个自定义的IConnectionProvider接口的实现,它不属于NHibernate)。

hibernate.connection.driver_class
定制IDriver的类型.
full.classname.of.Driver (如果驱动类创建在NHibernate中), 或者 full.classname.of.Driver, assembly (如果使用一个自定义IDriver接口的实现,它不属于NHibernate)。

hibernate.connection.connection_string
用来获得连接的连接字符串.

hibernate.connection.isolation
设置事务隔离级别. 请检查 System.Data.IsolationLevel 来得到取值的具体意义并且查看数据库文档以确保级别是被支持的。
例如: Chaos, ReadCommitted, ReadUncommitted, RepeatableRead, Serializable, Unspecified

hibernate.dialect
NHibernate方言(Dialect)的类名 - 可以让NHibernate使用某些特定的数据库平台的特性
例如: full.classname.of.Dialect(如果方言创建在NHibernate中), 或者full.classname.of.Dialect, assembly (如果使用一个自定义的方言的实现,它不属于NHibernate)。

接着,我们开始解释代码的执行,如下:
CODE:
Configuration config = new Configuration().AddAssembly("Test.Model");

//通过配置对象来产生一个SessionFactory对象,这是一个Session工厂,
//那么Session是用来干什么的呢?一个Session就是由NHibernate封装
//的工作单元,我们可以近似地认为它起到ADO.Net中Connection的作用。
ISessionFactory factory = config.BuildSessionFactory();
ISession session = factory.OpenSession();

Person person = new Person();
person.Name = "Jackie Chan";

//这里,开启一个由NHibernate封装的事务,当然,在这里最终代表
//的还是一个真实的数据库事务,但是我们已经不需要再区分到底是
//一个SqlTransaction还是一个ODBCTransaction了
ITransaction trans = session.BeginTransaction();
try
{
  //保存,提交,就这么简单!!
      session.Save(person);
    trans.Commit();
    Console.WriteLine("Insert Success!");
}
catch (Exception ex)
{
    trans.Rollback();
    Console.WriteLine(ex.Message);
}


现在有了一个基本的概念了吧??
好了,第一篇就讲这么多,我们下次再接着练习。

Step by Step,顾名思义,是一步一步来的意思,整个教程我将贯彻这一理念,待此系列结束后,我们再就某些高级话题进行深入。
任何建议或者批评,请e:abluedog@163.com

[1 楼] Posted:2007-09-01 17:05| 顶端
lisirui





级别: 新手上路
精华: 0
发帖: 12
威望: 13 点
金钱: 120 RMB
注册时间:2007-09-01
查看作者资料 发送短消息 发送邮件 推荐此帖 引用回复这个帖子



NHibernate Step by Step(二) 单表操作

接着第一期,我们继续。

为了方便学习测试,从今天开始我将使用MS Test来进行测试,这样就避免了在一个Console工程里不停地添加、注释代码了。



提示:为了在VS2005IDE中获得NHibernate配置文件的代码提示,请将你的$NHibernate\src\NHibernate下的nhibernate-configuration-2.0.xsd、nhibernate-mapping-2.0.xsd拷贝到\Program Files\Microsoft Visual Studio 8\Xml\Schemas下,这样当你编辑配置文件或者映射文件时,你将得到完整的代码提示。
VS2003请拷贝到\Program Files\Microsoft Visual Studio .NET 2003\Common7\Packages\schemas\xml下。


NHibernat内部使用log4net来进行日志操作,今天我们将在配置文件中添加log4net的配置,这样我们在测试的时候将可以清楚地看到NHibernate是如何进行工作的。

应用配置文件修改如下:

CODE:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
  <section name="nhibernate" type="System.Configuration.NameValueSectionHandler, System,Version=1.0.5000.0,Culture=neutral, PublicKeyToken=b77a5c561934e089" />
  <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" />
</configSections>

<nhibernate>
  <add key="hibernate.connection.provider" value="NHibernate.Connection.DriverConnectionProvider" />
  <add key="hibernate.connection.driver_class" value="NHibernate.Driver.SqlClientDriver" />
  <add key="hibernate.connection.connection_string" value="Server=localhost;Initial Catalog=NHibernate;Integrated Security=SSPI" />
  <add key="hibernate.connection.isolation" value="ReadCommitted"/>
  <add key="hibernate.dialect" value="NHibernate.Dialect.MsSql2000Dialect" />
  <add key="show_sql" value="true" />
</nhibernate>

<log4net>
  <appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender" >
    <layout type="log4net.Layout.PatternLayout">
    <conversionPattern value="%date [%thread] %-5level %logger [%ndc] - %message%newline" />
    </layout>
  </appender>
  <root>
    <level value="ALL" />
    <appender-ref ref="ConsoleAppender" />
  </root>

</log4net>

</configuration>


请注意添加:
CODE:
<add key="show_sql" value="true" />



关于log4net的使用,我们这里不做详细的讲解,有兴趣的请参考如下地址:

http://logging./log4net/



接着,我们在上次的工程组中添加一个名为Test1的测试项目,将其中的不需要的手动测试去掉。请注意:除了NHibernate\Model引用外,还需要添加如下3个引用:

log4net,System.Data,System.Xml.



修改代码如下:
CODE:
using System;
using System.Text;
using System.Collections;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using NHibernate;
using NHibernate.Cfg;
using log4net;
using log4net.Config;
using Test.Model;

namespace Test1
{
  /**//// <summary>
  /// Summary description for UnitTest1
  /// </summary>
  [TestClass]
  public class UnitTest1
  {
    static ISessionFactory factory;
    static ILog logger;
    ISession session;

    public UnitTest1()
    {
    }

    Additional test attributes#region Additional test attributes
   
      [ClassInitialize()]
      public static void MyClassInitialize(TestContext testContext)
      {
        XmlConfigurator.Configure();
        logger = LogManager.GetLogger(typeof(Test1.UnitTest1));
        Configuration config = new Configuration().AddAssembly("Test.Model");
        factory = config.BuildSessionFactory();
      }
   
      [ClassCleanup()]
      public static void MyClassCleanup() { }
   
      [TestInitialize()]
      public void MyTestInitialize()
      {
        session = factory.OpenSession();
      }
   
      [TestCleanup()]
      public void MyTestCleanup()
      {
        session.Close();
      }
   
    #endregion
  }
}


我们在测试的开始对Configuration\SessionFactory\Log进行初始化。在每一个Test的开始获取一个新的session,每一个Test结束后即关闭session。



添加如下一个Get测试:
CODE:
[TestMethod]
public void TestRead()
{
    Person person = (Person)session.Get(typeof(Person), 1);
    Assert.IsTrue(person.Name == "Jackie Chan");
}


我们在前面曾经插入一条名为“Jackie Chan”的记录,现在在Test Manager中选中TestRead,运行,ok,Passed!
我们使用了session.Get来获取记录,方法如下:

object Get(Type clazz,object id);

很简单,一目了然。



我们切换到Test Results窗口,双击测试成功的TestRead方法,这时将会有一个详细的测试结果显示出来,NHibernate将使用我们指定的log4net来输出详细信息,我们仔细观察:
CODE:
2006-04-15 13:52:13,000 [AdpaterExeMgrThread1] DEBUG NHibernate.Impl.SessionImpl [(null)] - opened session

2006-04-15 13:52:13,015 [AdpaterExeMgrThread1] DEBUG NHibernate.Impl.SessionImpl [(null)] - loading [Person#1]

2006-04-15 13:52:13,015 [AdpaterExeMgrThread1] DEBUG NHibernate.Impl.SessionImpl [(null)] - attempting to resolve [Person#1]

2006-04-15 13:52:13,015 [AdpaterExeMgrThread1] DEBUG NHibernate.Impl.SessionImpl [(null)] - object not resolved in any cache [Test.Model.Person#1]

2006-04-15 13:52:13,015 [AdpaterExeMgrThread1] DEBUG NHibernate.Persister.EntityPersister [(null)] - Materializing entity: Test.Model.Person#1



2006-04-15 13:52:13,078 [AdpaterExeMgrThread1] DEBUG NHibernate.Impl.BatcherImpl [(null)] - Opened new IDbCommand, open IDbCommands :1

2006-04-15 13:52:13,078 [AdpaterExeMgrThread1] DEBUG NHibernate.Impl.BatcherImpl [(null)] - Building an IDbCommand object for the SqlString: SELECT person0_.id as id0_, person0_.name as name0_ FROM Person person0_ WHERE person0_.id=:id

2006-04-15 13:52:13,093 [AdpaterExeMgrThread1] DEBUG NHibernate.Type.Int32Type [(null)] - binding '1' to parameter: 0

2006-04-15 13:52:13,093 [AdpaterExeMgrThread1] INFO NHibernate.Loader.Loader [(null)] - SELECT person0_.id as id0_, person0_.name as name0_ FROM Person person0_ WHERE person0_.id=@p0

2006-04-15 13:52:13,093 [AdpaterExeMgrThread1] DEBUG NHibernate.SQL [(null)] - SELECT person0_.id as id0_, person0_.name as name0_ FROM Person person0_ WHERE person0_.id=@p0

2006-04-15 13:52:13,093 [AdpaterExeMgrThread1] DEBUG NHibernate.SQL [(null)] - @p0 = '1'



2006-04-15 13:52:13,093 [AdpaterExeMgrThread1] DEBUG NHibernate.Connection.DriverConnectionProvider [(null)] - Obtaining IDbConnection from Driver

2006-04-15 13:52:13,859 [AdpaterExeMgrThread1] DEBUG NHibernate.Impl.BatcherImpl [(null)] - Opened Reader, open Readers :1

2006-04-15 13:52:13,859 [AdpaterExeMgrThread1] DEBUG NHibernate.Loader.Loader [(null)] - processing result set

2006-04-15 13:52:13,875 [AdpaterExeMgrThread1] DEBUG NHibernate.Loader.Loader [(null)] - result row: 1

2006-04-15 13:52:13,875 [AdpaterExeMgrThread1] DEBUG NHibernate.Loader.Loader [(null)] - Initializing object from DataReader: 1

2006-04-15 13:52:13,875 [AdpaterExeMgrThread1] DEBUG NHibernate.Loader.Loader [(null)] - Hydrating entity: Test.Model.Person#1

2006-04-15 13:52:13,906 [AdpaterExeMgrThread1] DEBUG NHibernate.Type.StringType [(null)] - returning 'Jackie Chan' as column: name0_

2006-04-15 13:52:13,906 [AdpaterExeMgrThread1] DEBUG NHibernate.Loader.Loader [(null)] - done processing result set (1 rows)

2006-04-15 13:52:13,937 [AdpaterExeMgrThread1] DEBUG NHibernate.Driver.NHybridDataReader [(null)] - running NHybridDataReader.Dispose()

2006-04-15 13:52:13,937 [AdpaterExeMgrThread1] DEBUG NHibernate.Impl.BatcherImpl [(null)] - Closed Reader, open Readers :0

2006-04-15 13:52:13,937 [AdpaterExeMgrThread1] DEBUG NHibernate.Impl.BatcherImpl [(null)] - Closed IDbCommand, open IDbCommands :0

2006-04-15 13:52:13,937 [AdpaterExeMgrThread1] DEBUG NHibernate.Loader.Loader [(null)] - total objects hydrated: 1

2006-04-15 13:52:13,953 [AdpaterExeMgrThread1] DEBUG NHibernate.Impl.SessionImpl [(null)] - resolving associations for: [Test.Model.Person#1]

2006-04-15 13:52:13,953 [AdpaterExeMgrThread1] DEBUG NHibernate.Impl.SessionImpl [(null)] - done materializing entity [Test.Model.Person#1]

2006-04-15 13:52:13,953 [AdpaterExeMgrThread1] DEBUG NHibernate.Impl.SessionImpl [(null)] - initializing non-lazy collections

2006-04-15 13:52:13,953 [AdpaterExeMgrThread1] DEBUG NHibernate.Impl.SessionImpl [(null)] - closing session

2006-04-15 13:52:13,953 [AdpaterExeMgrThread1] DEBUG NHibernate.Impl.SessionImpl [(null)] - disconnecting session

2006-04-15 13:52:13,953 [AdpaterExeMgrThread1] DEBUG NHibernate.Connection.ConnectionProvider [(null)] - Closing connection

2006-04-15 13:52:13,968 [AdpaterExeMgrThread1] DEBUG NHibernate.Impl.SessionImpl [(null)] - transaction completion



在其中,我们可以发现:

CODE:
2006-04-15 13:52:13,093 [AdpaterExeMgrThread1] DEBUG NHibernate.SQL [(null)] - SELECT person0_.id as id0_, person0_.name as name0_ FROM Person person0_ WHERE person0_.id=@p0

2006-04-15 13:52:13,093 [AdpaterExeMgrThread1] DEBUG NHibernate.SQL [(null)] - @p0 = '1'




对了,就是这里,NHibernate替我们构造了一条sql语句,并添加一个参数,然后将我们在代码中赋的id值1来填充,这样,一条完整的可以执行的sql语句产生了。

请注意:在产生sql语句的前面,NHibernate构造了一个IDBCommand,然后在sql语句产生完全后,获取连接,通过一个DataReader来填充Persion对象给我们使用,这就是NHibernate替我们做的事,是不是很简单啊?(真的很简单吗??看看源代码吧!!)

请仔细研究输出的日志。



如法炮制,我们添加另外3个Test,完成单个表的全部CRUD操作,如下完整代码:
CODE:
[TestMethod]

    public void TestCreate()

    {

        Person person = new Person();

        person.Name = "Jackie Chan";



        ITransaction trans = session.BeginTransaction();

        try

        {

          session.Save(person);

          trans.Commit();

          Assert.IsTrue(person.Id > 0);

        }

        catch (Exception ex)

        {

          trans.Rollback();

          Assert.Fail(ex.Message);

        }

    }



    [TestMethod]

    public void TestUpdate()

    {

        Person person = (Person)session.Get(typeof(Person), 1);

        person.Name = "Jet Li";



        ITransaction trans = session.BeginTransaction();

        try

        {

          session.Save(person);

          trans.Commit();

          Assert.IsTrue(person.Name == "Jet Li");

        }

        catch (Exception ex)

        {

          trans.Rollback();

          Assert.Fail(ex.Message);

        }

    }



    [TestMethod]

    public void TestRead()

    {

        Person person = (Person)session.Get(typeof(Person), 1);

        Assert.IsTrue(person.Name == "Jackie Chan");

    }



    [TestMethod]

    public void TestDelete()

    {

        Person person = (Person)session.Get(typeof(Person), 1);



        ITransaction trans = session.BeginTransaction();

        try

        {

          session.Delete(person);

          trans.Commit();

        }

        catch (Exception ex)

        {

          trans.Rollback();

          Assert.Fail(ex.Message);

        }

    }



Delete的方法如下:

void Delete(object obj);

直接传入需要delete的对象即可。



好了,基本的操作都完成了,是不是很Easy?
好了,这一篇就讲这么多,我们下次再接着练习。


Step by Step,顾名思义,是一步一步来的意思,整个教程我将贯彻这一理念。

任何建议或者批评,请e:abluedog@163.com

[2 楼] Posted:2007-09-01 17:08| 顶端
lisirui





级别: 新手上路
精华: 0
发帖: 12
威望: 13 点
金钱: 120 RMB
注册时间:2007-09-01
查看作者资料 发送短消息 发送邮件 推荐此帖 引用回复这个帖子



NHibernate Step by Step (三) Configuration和Sessionfactory

好了,我们再从头看一看Configuration,是否只能从App.config中取配置信息??

当然不是了,以下是3种最常见的配置:

<1> Configuration config = new Configuration();

这种配置方法将会到应用程序配置文件(App.Config,Web.Config)中查找NHibernate的配置信息,NHibernate的配置节必须符合应用程序配置文件个格式,前面的教程我们已经看到过了。

<2> Configuration config = new Configuration().Configure();

    这种配置方法将会在应用的相同目录查找名为”hibernate.cfg.xml”的标准Hibernate配置

    文件,格式如下:

CODE:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.0" >

    <session-factory name="MySessionFactory">

        <!-- properties -->
        <property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
        <property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
        <property name="connection.connection_string">Server=localhost;initial catalog=Hibernate;Integrated Security=SSPI</property>
        <property name="show_sql">false</property>
        <property name="dialect">NHibernate.Dialect.MsSql2000Dialect</property>
        <property name="use_outer_join">true</property>
        <property name="query.substitutions">true 1, false 0, yes 'Y', no 'N'</property>

        <!-- mapping files -->
        <mapping assembly="Test.Model" />
    </session-factory>
</hibernate-configuration>


    <3> Configuration config = new Configuration().Configure(configFileName);

    这种配置方法将查找指定的Hibernate标准配置文件,可以是绝对路径或者相对路径。

    另外我们还可以通过编码的方式添加配置信息:

 
CODE:
 

Hashtable props = new Hashtable();
props[“dialect”] = xxxx;



config.Properties = props;



    这种方式不够配置文件来的灵活,所以我们一般不建议使用。



在取得config后,我们还需要进行映射文件添加,同样,我们常用以下3种不同的方法:

CODE:

<1> config.AddXmlFile(“Person.hbm.xml”);

<2> config.AddClass(typeof(Test.Model.Person));

<3> config.AddAssembly(“Test.Model”);



以上方法都可以用“阶梯式“的编码风格,如下:
 
CODE:

config.AddXmlFile(“Person.hbm.xml”)

    .AddXmlFile(“User.hbm.xml”)

    .AddClass(typeof(Test.Model.Customer));




当然,为了方便起见,我们一般把所有的影射类文件及xml文件统一放在一个程序集中,然后使用config.AddAssembly(assemblyName)的方式,让NHibernate自动去查找指定程序集中所有的映射文件和映射类。

你有没有发现在我们使用标准的hibernate配置文件时,有如下一个元素:

<!-- mapping files -->

<mapping assembly="Test.Model" />

对了,你想的不错,我们可以避免在代码中捆绑映射程序集,而在配置文件中指定,这种方式可以说是最灵活的了。

提示:在Web程序中,最好将配置文件改为config的后缀,否则在没有添加对xml的asp.net映射的情况下,你的配置文件就有可能被下载哟!!



我们再来看看Sessionfactory:

CODE:


ISessionFactory sessionFactory = config.BuildSessionFactory();


在由Configuration构造完SessionFactory后,SessionFactory便保留了配置信息而不再需要Configuration,之后Configurationd的任何变化都不会影响到已经创建好的SessionFactory,如果你的配置信息发生变化,那么,毋庸置疑,你必须重新由Configuration构造出一个新的SessionFactory来。

注意:SessionFactory是一个Heavy Object,它不但保存了配置信息,而且还有所有的映射关系(你可以调用GetAllCollectionMetadata方法试验一下),以及需要进行总体维护的缓存等等信息,所以,我们不应该重复地创建SessionFactory对象,而应该充分共用已经创建出来的SessionFactory对象,同时,SessionFactory也是一个线程安全的对象,所以在多线程的场景下也完全可以共用。在我们实际开发中,我们可以在初始化的部分构造一个SessionFactory即可,比如,在一个公共静态类中初始化一个SessionFactory的readonly常量等等。



另外需要注意的是,如果你要对多个数据库进行操作,那么你可以配置针对每个数据库而创建对应的SessionFactory——大部分情况下,一个数据库对应一个SessionFactory足够使用。



好了,这一篇就讲这么多,我们下次再接着练习。
任何建议或者批评,请e:abluedog@163.com

[3 楼] Posted:2007-09-01 17:11| 顶端
lisirui





级别: 新手上路
精华: 0
发帖: 12
威望: 13 点
金钱: 120 RMB
注册时间:2007-09-01
查看作者资料 发送短消息 发送邮件 推荐此帖 引用回复这个帖子



NHibernate Step by Step (四)Session、Query及HQL




我们总结一下在第二篇中的Session操作:

1. 获取记录


CODE:

Person person = (Person)session.Get(typeof(Person),1);


2. 保存记录
CODE:

session.Save(person);


3. 删除记录

CODE:

Person person = (Person)session.Get(typeof(Person),1);

session.Delet(person);




我们再来看看其它几种方式:

1. Load

CODE:

Person person = (Person)session.Load(typeof(Person),1);


是不是感觉和Get一样?其实……很不一样!

Get在找不到对象时会返回一个null引用,而Load则会抛出一个ObjectNotFoundException,所以,不应该用Load来判断记录是否存在。另外还有两条非常重要的区别,我们将放在高级话题讨论。

2. Query

CODE:

IList list = session.CreateQuery(“from Person”).List();

Person person = (Person)list[0];


    ~!#@^?? from Person??#$@*&^$

    这是虾米??

    好象有点象SQL,不过少了个select啊!而且也没有表名啊!

    这就是久负盛名的HQL——Hibernate Query Language!

    HQL实际上是基于对象查询的一种仿SQL脚本,在运行期间,Hibernate会自动根据映射关系将之转换为真正的SQL语句来执行。

    什么?又一种SQL?不是说使用O/R Mapping就可以不写SQL了吗,怎么又多了一种“SQL”??

    当然不是这样了,之所以产生HQL,就是为了能够更加灵活更加面向对象地操作数据,而且你不应该把HQL当成一种新的SQL,因
  为它——太简单好学了!

    看看下面的HQL,是不是很熟悉??

CODE:
   

select p.Name from Person as p where p.Id=1
select Name from Person where Age>20
select Id,Name from Person where Id>1 and Age>20




    认出来老兄弟了吧!!

    (从这里开始,我们给person表添加了一个age列,请注意)

    ok,我们这里就详细解释。

    “from Person ”意思是取出Person类映射的person表中的所有记录,对应的SQL是:

    “Select * from person”

    还可以加上别名:from Person (as) p = Select * from person (as) p

    这样一解释就很清楚了吧!一句话,你便已经掌握了HQL的50%!

    而“select Name from Person”,当然也就是只取person表的name列了!

    你所知道的where中的and、or、is、like、between、>、<、=等等都可以直接拿来使用,

    如下:

CODE:
 

select p.Name from Person p where p.Age>20

from Person p where p.Age between 20 and 30

from person p where p.Age in (20,30)

from person p where p.Name is null

from person p where p.Name like “Jaki%”
 
 

    注意:字段大小写应该尽量跟属性名称保持一致,尤其是在使用别名的情况下,如:

    p.age将会导致一个“无法解析属性age“的错误。但是在不使用别名的情况下我的机器上”age“和’Age“一样可以通过,虽然如此,
  建议还是跟类文件保持一致。



执行HQL是通过IQuery来实现的,如下是详细的写法:

CODE:

IQuery query = session.CreateQuery(“from Person”);

IList list = query.List();



  通过session来创建一个query,然后执行query的List方法,返回符合条件的IList。

如上面的“from Person“,将返回person表的所有记录,list中将包含映射到Person类

的对应表中所有记录的对象。



好了,这一篇就讲这么多,我们下次再接着练习。
任何建议或者批评,请e:abluedog@163.com

[4 楼] Posted:2007-09-01 17:13| 顶端
lisirui





级别: 新手上路
精华: 0
发帖: 12
威望: 13 点
金钱: 120 RMB
注册时间:2007-09-01
查看作者资料 发送短消息 发送邮件 推荐此帖 引用回复这个帖子



NHibernate Step by Step (五)Criteria Query

可能很多人象我一样,刚开始接触HQL时,脑袋一片混沌,这是什么语法嘛!!之所以这样,是因为我们总是会先入为主地将之与SQL想比,虽然HQL看起来很SQL,而且设计时就有这样的意图,但是毕竟是两种差别很大的东西,难免就会出现理解偏差的问题。好了,我们今天就不让大家脑袋发晕了,HQL我们暂时放一放。今天我们来说另外一种查询方法:

CODE:

Criteria Query.


什么是Criteria Query?简单说,就是将我们的查询条件封装为一个预定义的查询对象,由这个查询对象来执行查询,而不用我们再去写HQL了,而且更接近我们贯常的编程习惯。

是不是很不错?让我们来look look:

CODE:

//创建关联到某个类的查询对象
ICriteria criteria = session.CreateCriteria(typeof(Person));

//添加表达式
criteria.Add(Expression.Eq("Name","Jackie Chan"));

IList list = criteria.List();



注意这一句:

CODE:

Expression.Eq("Name","Jackie Chan")


Eq是Equal的缩写,意思是添加一个查询表达式,Person.Name = “Jackie Chan”

对应HQL就是:
CODE:

from Person p where p.Name=”Jackie Chan”


NHibernate会在运行时动态生成类似上面的HQL,我们可以在配置文件把show-sql打开,观看生成的SQL。

这样是不是感觉清晰多了?又回到我们以前的编码习惯了!


为了对应HQL的种种查询条件,NHibernate预定义了大量的Expression方法,我们列几个如下:

CODE:

Eq       = Equal
Gt       = Greater than
Lt       = Less than
Like     = Like
Not       = Not
IsNull     = Is Null

基本上对应了大部分HQL的语义,详细的说明请参考api。


下面,我们详细介绍Criteria的用法。

1. Example查询


我们常常有这样的查询页面:

用户可以输入“姓名”、“性别”、“年龄”等等来进行查询,而我们常常的做法就是如下的烦琐:

CODE:

string condition = “”;
if(txtName.Text != null)
    condition += “ Name=” + txtName.Text;

if(txtSex.Text != null)
    condition += “ and Sex=” + txtSex.Text;

……



代码看起来实在是不甚美观,有什么解决办法呢?

Criteria提供了专为这种问题而设计的Example查询,如下:

CODE:


ICriteria criteria = session.CreateCriteria(typeof(Person));

Person person = new Person();
person.Name = "Jackie Chan";
person.Age = 50;

//创建一个Example对象
criteria.Add(Example.Create(person));
IList list = criteria.List();


请注意:

CODE:

criteria.Add(Example.Create(person));


这句代码的意思是通过构造的person对象的属性来生成表达式,实际生成的代码如下:


CODE:

SELECT this.id as id0_, this.name as name0_, this.age as age0_ FROM Person this WHERE (this.age = @p0)


对应上面的问题,我们简单地new出一个person对象,然后填充其属性即可,不用再去构造那丑陋的条件判断语句了!


2. 排序

我们想对返回的list进行排序,该怎么办呢?如下:

CODE:

ICriteria criteria = session.CreateCriteria(typeof(Person));
criteria.Add(Expression.Gt("Age", 20));

//添加一个排序对象
criteria.AddOrder(Order.Asc("Age"));

IList list = criteria.List();




请注意:

CODE:


criteria.AddOrder(Order.Asc("Age"));


这句代码的意思是在criteria上构造一个排序对象,并以Age属性做正序排列,NHibernate在运行时会生成如下语句:

CODE:


SELECT this.id as id0_, this.name as name0_, this.age as age0_ FROM Person this WHERE this.age > @p0 ORDER BY this.age asc


如你所猜想,Order类肯定有另外一个“Desc“方法:)


3. 限制记录范围

在显示大量的记录时,我们常常采用的方法就是分页,如果用NHibernate来做,该怎么办呢?

如下代码:

CODE:

ICriteria criteria = session.CreateCriteria(typeof(Person));

//从第10条记录开始取
criteria.SetFirstResult(10);

//取20条记录
criteria.SetMaxResults(20);

IList list = criteria.List();


这样,我们就达到了分页的目的。

注意:

NHibernate的分页机制实际上依赖于不同的数据库实现,所以,对特定的某种数据库,并不一定是效率最好的,比如对SQLServer(为什么受伤的总是俺?为什么总是说俺比不上Oracle?俺都赶在2005年年底出2005版本了!!)。想知道为什么吗?很简单,check一下上面代码生成的SQL就清楚了!或者深入点再看看NHibernate的分页代码,我就不解释了,自己动手,丰衣足食:)


总体来讲,Criteria对我们来说更熟悉,更容易上手,但是目前Criteria还是不够完善——将对应的HQL一一封装实在太烦琐了,所以NHibernate还是以HQL查询为主,我们在使用的时候则看需要了,要么使用HQL,要么HQL和Criteria混合使用,重要的是解决问题,对不?


好了,这一篇就讲这么多,我们下次再接着练习。
任何建议或者批评,请e:abluedog@163.com

[5 楼] Posted:2007-09-01 17:16| 顶端
 

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多