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()创建的是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; }
最终生成了一个SessionImpl对象, 相对于创建一个SessionFactory的过程, 创建一个Session的开销相对小很多.
执行session.Save(employee)方法, 这时就往数据库表employee新增一条记录了, 同时, NHiberante会把自动生成的Id值读取到employee.Id中, 所以接下来的Console.WriteLine(employee.Id.ToString() + employee.Name)就可以成功地打印出来了.

浙公网安备 33010602011771号