Learing NHibernate 2nd

  在上一篇中Learning NHibernate 1th中, 详细介绍了如何配置NHibernate的数据库信息, 接下来这一篇就要以一个简单的实例为接入点, 开始学习如何使用NHibernate.

数据库表的创建

USE Test;

CREATE TABLE employee
(    employee_id INT IDENTITY(1,1) NOT NULL,
     employee_name NVARCHAR(50) NOT NULL,
     CONSTRAINT pk_employee PRIMARY KEY(employee_id)    );

创建实体类

namespace ConsoleApp
{
    public class Employee
    {
        public virtual int Id { get; set; }
        public virtual string Name { get; set; }
    }
}

  定义实体类的时候, 属性必须设置为virtual, 否则系统会报错.

编写配置文件

   在ConsoleApp下新建一个Employee.hbm.xml文件, 同时为xml文件新增架构schema, 添加nhibernate-mapping.xsd的引用(以支持智能提示), 写入内容如下:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="ConsoleApp" assembly="ConsoleApp">
  <class name="Employee" table="employee">
    <id name="Id" column="employee_id">
      <generator class="native"></generator>
    </id>
    <property name="Name" column="employee_name"></property>
  </class>
</hibernate-mapping>

  最后设置该文件的属性"生成操作"为“嵌入的资源”, 这点非常重要, 因为NHibernate在加载Mappings的时候, 会自动去程序集中查找hbm.xml的文件, 如果没有把该文件嵌入到资源中, 则实体类的映射将不会完成.

hibernate-mapping表示根节点, namespace表示所对应的实体类的命名空间, assembly表示所对应的实体类的程序集名称.

class表示映射的实体类, name表示实体类的名称, table表示数据库的表名称, 假如数据表的名称与实体类的名称一致, 则table属性可以省略.

id是每个class节点下必须存在的节点, 起到主键识别的作用, 同样name表示实体类中的属性, column表示对应的table表中的列名称, 同样假如表列名与实体类的属性名称一致, 则这个column属性可以省略. generator节点位于id节点下, 表示id的生成方式, 这里配置的class= “native”表示主键生成方式会自动根据数据库的底层实现选择Identity实现.

property节点比较简单, 表示实体类属性到表列的映射.

开始使用NHibernate

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NHibernate;
using NHibernate.Cfg;

namespace ConsoleApp
{
    class Program
    {
        static void CreateNewEmployee()
        {
            Employee employee = new Employee { Name = "student" };
            ISessionFactory sessionFactory = new Configuration().Configure().BuildSessionFactory();
            ISession session = sessionFactory.OpenSession();
            session.Save(employee);
            Console.WriteLine(employee.Id.ToString() + employee.Name);
        }

        static void Main(string[] args)
        {
            CreateNewEmployee();
        }
    }
}

  首先, 先建立一个Emploee对象, 同时设置Name属性的值, 这里要注意的是因为Employee.hbm.xml文件已经把Id属性设置为数据库自动生成, 所以这里就无需提供Id的值了.

  接下来就创建一个SessionFactory, 由上一篇文章Learning NHibernate 1th可以知道, 这一步开销非常大, 所以我们基本不可能在每次需要建立数据库连接的时候新建一个SessionFactory, 后续文章中, 这个创建过程将会使用单例模式进行封装, 从而减少开销.

  下一步就是建立一个Session, Session表示一次会话状态, 也可以理解为单元工作模式(unit of work). 再次使用ILSpy查看NHibernate的源码, 如下:

public ISessionFactory BuildSessionFactory()
{
    this.ConfigureProxyFactoryFactory();
    this.SecondPassCompile();
    this.Validate();
    Environment.VerifyProperties(this.properties);
    Settings settings = this.BuildSettings();
    this.Schemas = null;
    return new SessionFactoryImpl(this, this.mapping, settings, this.GetInitializedEventListeners());
}
BuildSessionFactory()方法执行过程

  可见, BuildSessionFactory()创建的是SessionFacoryImpl的对象. SessionFactotryImpl对象OpenSession()执行的过程如下:

public ISession OpenSession()
{
    return this.OpenSession(this.interceptor);
}

public ISession OpenSession(IInterceptor sessionLocalInterceptor)
{
    if (sessionLocalInterceptor == null)
    {
        throw new ArgumentNullException("sessionLocalInterceptor");
    }
    long timestamp = this.settings.CacheProvider.NextTimestamp();
    return this.OpenSession(null, true, timestamp, sessionLocalInterceptor);
}

private SessionImpl OpenSession(IDbConnection connection, bool autoClose, long timestamp, IInterceptor sessionLocalInterceptor)
{
    SessionImpl session = new SessionImpl(connection, this, autoClose, timestamp, sessionLocalInterceptor ?? this.interceptor, this.settings.DefaultEntityMode, this.settings.IsFlushBeforeCompletionEnabled, this.settings.IsAutoCloseSessionEnabled, this.settings.ConnectionReleaseMode);
    if (sessionLocalInterceptor != null)
    {
        sessionLocalInterceptor.SetSession(session);
    }
    return session;
}
OpenSession执行流程

  最终生成了一个SessionImpl对象, 相对于创建一个SessionFactory的过程, 创建一个Session的开销相对小很多.

  执行session.Save(employee)方法, 这时就往数据库表employee新增一条记录了, 同时, NHiberante会把自动生成的Id值读取到employee.Id中, 所以接下来的Console.WriteLine(employee.Id.ToString() + employee.Name)就可以成功地打印出来了.

posted @ 2013-11-29 11:58  teroy  阅读(180)  评论(0)    收藏  举报