首页 > 代码库 > [NHibernate]基本配置与测试
[NHibernate]基本配置与测试
目录
写在前面
nhibernate文档
搭建项目
映射文件
持久化类
辅助类
数据库设计与连接配置
测试
总结
写在前面
一年前刚来这家公司,发现项目中使用的ORM是Nhibernate,这个之前确实没接触过,EF多少在项目中用过,想着既然都是ORM,应该语法上都差不多。当时也就是硬着头皮上的,刚开始也只能通过模仿别人的代码,再加上自己的理解,一些增删改查的方法,确实也被自己给搞出来了,现在回头想想,在项目中,用到的那些方法基本上就一个样,很少有变化。除非有些业务逻辑非常强的,自己搞不定,问一下同事,还是可以解决的。到现在使用Nhibernate也很长时间,中间多少也查过一些资料,从网上下的nhibernate文档.docx,但是每次想去找的时候,总的在电脑上去找,比较麻烦,就干脆记录在博客中了,当时就是有哪些不明白的,可以很方便的从里面查,比如参数是什么含义。也总结了一些,在使用过程遇到的问题。
现在项目告一段落,坐等为客户去部署了,也就有那么点空闲时间,那就要系统的学习一下了。
发现在写这篇文章的时候,说了自己的一些学习方式,发现越写越多,就单独成篇了,也就有了这篇文章——如何高效的利用博客园?
上篇文章,也算是nhibernate学习的开篇吧。
nhibernate文档
[Nhibernate]体系结构
[NHibernate]ISessionFactory配置
[NHibernate]持久化类(Persistent Classes)
[NHibernate]O/R Mapping基础
[NHibernate]集合类(Collections)映射
[NHibernate]关联映射
[NHibernate]Parent/Child
[NHibernate]缓存(NHibernate.Caches)
[NHibernate]NHibernate.Tool.hbm2net
[NHibernate]Nullables
[NHibernate]Nhibernate如何映射sqlserver中image字段
搭建项目
项目结构和映射文件
项目结构说明
采用传统三层架构
Wolfy.Shop.Domain:数据实体和数据库映射文件。也有人叫做领域层。
Wolfy.Shop.Data:数据层,存放数据库的操作及Nhibernate辅助类。引用Iesi.Collections.dll,NHibernate.dll和类库Wolfy.Shop.Domain
Wolfy.Shop.Business:业务逻辑类。引用类库项目Wolfy.Shop.Domain,Wolfy.Shop.Data
Wolfy.Shop.WebSite:测试项目。需引用Iesi.Collections.dll,NHibernate.dll和类库项目Wolfy.Shop.Domain,Wolfy.Shop.Business
Nhibernate最新版本为4.0.1.GA,下载地址:http://nhforge.org/
解压NHibernate-4.0.1.GA-bin.zip压缩包,内容如下:
其中Confiuration_Templates文件夹内包括:
这些xml内为数据库连接配置文件模版,通过上图也可以发现nhibernate支持的数据库种类还是很全的。主流的数据库已经都包括在内了。
那么,咱们打开MSSQL.cfg的文件看一下
1 <?xml version="1.0" encoding="utf-8"?> 2 <!-- 3 This template was written to work with NHibernate.Test. 4 Copy the template to your NHibernate.Test project folder and rename it in hibernate.cfg.xml and change it 5 for your own use before compile tests in VisualStudio. 6 --> 7 <!-- This is the System.Data.dll provider for SQL Server --> 8 <hibernate-configuration xmlns="urn:nhibernate-configuration-2.2" > 9 <session-factory name="NHibernate.Test">10 <property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>11 <property name="connection.connection_string">12 Server=(local);initial catalog=nhibernate;Integrated Security=SSPI13 </property>14 <property name="dialect">NHibernate.Dialect.MsSql2008Dialect</property>15 </session-factory>16 </hibernate-configuration>
通过上面的注释部分咱们可以得到一个信息,就是在项目中使用的话,需要将文件重命名为hibernate.cfg.xml.
添加引用
同样可以通过Nuget进行添加,如图:
持久化类
为客户实体创建持久化类
1 namespace Wolfy.Shop.Domain.Entities 2 { 3 /// <summary> 4 /// 描述:客户实体,数据库持久化类 5 /// 创建人:wolfy 6 /// 创建时间:2014-10-16 7 /// </summary> 8 public class Customer 9 {10 /// <summary>11 /// 客户id12 /// </summary>13 public virtual Guid CustomerID { get; set; }14 /// <summary>15 /// 客户名字16 /// </summary>17 public virtual string CustomerName { get; set; }18 /// <summary>19 /// 客户地址20 /// </summary>21 public virtual string CustomerAddress { get; set; }22 }23 }
编写映射文件
编写NHibernate配置文件智能提示的功能。只要在下载的NHibernate里找到configuration.xsd和nhibernate-mapping.xsd两个文件并复制到vs安装目录下,如C:\Program Files\Microsoft Visual Studio 9.0\Xml\Schemas目录即可。
此时,你在nhibernate的配置文件中就有智能提示功能了。
nhibernate如何知道持久化类和数据库表的对应关系的呢?这就要通过映射文件来完成这个任务了,映射文件包含了对象/关系映射所需的元数据。元数据包含持久化类的声明和属性到数据库的映射。映射文件告诉nhibernate它应该访问数据库里面的哪个表及使用表里面的哪些字段。
那么我们编写Customer持久化类的映射文件,注意映射文件以.hbm.xml结尾。如Customer.hbm.xml
1 <?xml version="1.0" encoding="utf-8" ?> 2 <!--assembly:程序集,namespace:命名空间--> 3 <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Wolfy.Shop.Domain" namespace="Wolfy.Shop.Domain.Entities"> 4 <class name="Wolfy.Shop.Domain.Entities.Customer,Wolfy.Shop.Domain" table="TB_Customer"> 5 <!--主键--> 6 <id name="CustomerID" type="Guid" unsaved-value="null"> 7 <column name="CustomerID" sql-type="uniqueidentifier" not-null="true" unique="true"/> 8 <generator class="assigned"></generator> 9 </id>10 <property name="CustomerName" type="String">11 <column name="CustomerName" sql-type="nvarchar" not-null="false"/>12 </property>13 <property name="CustomerAddress" type="String">14 <column name="CustomerAddress" sql-type="nvarchar" not-null="false"/>15 </property>16 17 </class>18 </hibernate-mapping>
这些东西该怎么记?记住根节点hibernate,并且映射文件中要有主键id和property节点就可以了,其他的依赖vs的智能提示,就可以了。
这里需要养成一个习惯,就写好映射文件,需要修改它的属性
否则会出现,如下错误,而这个错误也是使用nhibernate最常见,所以养成一个好习惯,能提高你的开发效率:
辅助类
在使用之前,需要通过ISessionFactory获得ISession,ISessionFactory的详细介绍可以参考文档[NHibernate]ISessionFactory配置 ,ISessionFactory是线程安全的,而ISession是非线程安全的。很多线程可以同时访问ISessionFactory,所以ISession要通过ISessionFactory打开,在所有的工作完成后,需要关闭。ISessionFactory通常是个线程安全的全局对象,只需要被实例化一次(可以使用单例模式)。这里编写一个简单的辅助类NHibernateHelper,用于创建ISessionFactory和配置ISessionFactory,并打开一个新的ISession的方法。代码如下:
1 using NHibernate; 2 using NHibernate.Cfg; 3 using System; 4 using System.Collections.Generic; 5 using System.Linq; 6 using System.Text; 7 using System.Threading.Tasks; 8 9 namespace Wolfy.Shop.Data10 {11 /// <summary>12 /// 描述:nhibernate辅助类13 /// 创建人:wolfy14 /// 创建时间:2014-10-1615 /// </summary>16 public class NHibernateHelper17 {18 private ISessionFactory _sessionFactory;19 public NHibernateHelper()20 {21 //创建ISessionFactory22 _sessionFactory = GetSessionFactory();23 }24 /// <summary>25 /// 创建ISessionFactory26 /// </summary>27 /// <returns></returns>28 public ISessionFactory GetSessionFactory()29 {30 //配置ISessionFactory31 return (new Configuration()).Configure().BuildSessionFactory();32 }33 /// <summary>34 /// 打开ISession35 /// </summary>36 /// <returns></returns>37 public ISession GetSession()38 {39 return _sessionFactory.OpenSession();40 }41 }42 43 }
这里需引入命名空间:NHibernate和NHibernate.Cfg。
数据库设计与连接配置
数据表设计如图所示:
创建数据表的sql
1 USE [Shop] 2 GO 3 /****** Object: Table [dbo].[TB_Customer] Script Date: 2014/10/16 17:56:27 ******/ 4 SET ANSI_NULLS ON 5 GO 6 SET QUOTED_IDENTIFIER ON 7 GO 8 CREATE TABLE [dbo].[TB_Customer]( 9 [CustomerID] [uniqueidentifier] NOT NULL,10 [CustomerName] [nvarchar](16) NULL,11 [CustomerAddress] [nvarchar](128) NULL,12 CONSTRAINT [pk_customerid] PRIMARY KEY CLUSTERED 13 (14 [CustomerID] ASC15 )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]16 ) ON [PRIMARY]17 18 GO19 /****** Object: Table [dbo].[TB_Order] Script Date: 2014/10/16 17:56:28 ******/20 SET ANSI_NULLS ON21 GO22 SET QUOTED_IDENTIFIER ON23 GO24 CREATE TABLE [dbo].[TB_Order](25 [OrderID] [uniqueidentifier] NOT NULL,26 [OrderDate] [uniqueidentifier] NULL,27 [CustomerID] [uniqueidentifier] NULL,28 CONSTRAINT [PK_TB_Order] PRIMARY KEY CLUSTERED 29 (30 [OrderID] ASC31 )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]32 ) ON [PRIMARY]33 34 GO35 /****** Object: Table [dbo].[TB_OrderProduct] Script Date: 2014/10/16 17:56:28 ******/36 SET ANSI_NULLS ON37 GO38 SET QUOTED_IDENTIFIER ON39 GO40 CREATE TABLE [dbo].[TB_OrderProduct](41 [OrderID] [uniqueidentifier] NOT NULL,42 [ProductID] [uniqueidentifier] NOT NULL43 ) ON [PRIMARY]44 45 GO46 /****** Object: Table [dbo].[TB_Product] Script Date: 2014/10/16 17:56:28 ******/47 SET ANSI_NULLS ON48 GO49 SET QUOTED_IDENTIFIER ON50 GO51 CREATE TABLE [dbo].[TB_Product](52 [ProductID] [uniqueidentifier] NOT NULL,53 [Name] [nvarchar](128) NULL,54 [Price] [decimal](18, 0) NULL,55 CONSTRAINT [PK_TB_Product] PRIMARY KEY CLUSTERED 56 (57 [ProductID] ASC58 )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]59 ) ON [PRIMARY]60 61 GO62 ALTER TABLE [dbo].[TB_Order] WITH CHECK ADD CONSTRAINT [FK_TB_Order_TB_Customer] FOREIGN KEY([CustomerID])63 REFERENCES [dbo].[TB_Customer] ([CustomerID])64 GO65 ALTER TABLE [dbo].[TB_Order] CHECK CONSTRAINT [FK_TB_Order_TB_Customer]66 GO67 ALTER TABLE [dbo].[TB_OrderProduct] WITH CHECK ADD CONSTRAINT [FK_TB_OrderProduct_TB_Order] FOREIGN KEY([OrderID])68 REFERENCES [dbo].[TB_Order] ([OrderID])69 GO70 ALTER TABLE [dbo].[TB_OrderProduct] CHECK CONSTRAINT [FK_TB_OrderProduct_TB_Order]71 GO72 ALTER TABLE [dbo].[TB_OrderProduct] WITH CHECK ADD CONSTRAINT [FK_TB_OrderProduct_TB_Product] FOREIGN KEY([ProductID])73 REFERENCES [dbo].[TB_Product] ([ProductID])74 GO75 ALTER TABLE [dbo].[TB_OrderProduct] CHECK CONSTRAINT [FK_TB_OrderProduct_TB_Product]76 GO
nhibernate配置,也就是数据库配置:
这里使用的是SQL Server2012,所以我们使用MSSQL.cfg.xml文件,重命名为hibernate.cfg.xml.
注意需根据自己数据库的实例名修改,并添加mapping节点,其他的设置,可根据需要进行添加。这里采用最简单的一种方式,关于nhibernate的配置参数,可参考文档中的说明。
1 1 <?xml version="1.0" encoding="utf-8" ?> 2 2 <hibernate-configuration xmlns="urn:nhibernate-configuration-2.2" > 3 3 <session-factory> 4 4 <property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property> 5 5 <property name="connection.connection_string"> 6 6 server=.;database=shop;uid=sa;pwd=sa 7 7 </property> 8 8 <property name="dialect">NHibernate.Dialect.MsSql2008Dialect</property> 9 9 <mapping assembly="Wolfy.Shop.Domain"/>10 10 </session-factory>11 11 </hibernate-configuration>
修改后,将hibernate.cfg.xml拷入Wolfy.Shop.WebSite项目,并修改其属性:
否则会出现如下异常:
数据层和业务逻辑层代码
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 using Wolfy.Shop.Domain.Entities; 7 using NHibernate; 8 using NHibernate.Linq; 9 using NHibernate.Cfg;10 using System.Linq.Expressions;11 namespace Wolfy.Shop.Data12 {13 /// <summary>14 /// 描述:客户数据层类,操作数据库15 /// 创建人:wolfy16 /// 创建时间:2014-10-1617 /// </summary>18 public class CustomerData19 {20 /// <summary>21 /// 添加客户22 /// </summary>23 /// <param name="customer">客户实体</param>24 /// <returns>是否添加成功 </returns>25 public bool AddCustomer(Customer customer)26 {27 28 try29 {30 NHibernateHelper nhibernateHelper = new NHibernateHelper();31 var session = nhibernateHelper.GetSession();32 session.SaveOrUpdate(customer);33 session.Flush();34 return true;35 }36 catch (Exception ex)37 {38 throw ex;39 }40 }41 /// <summary>42 /// 根据条件得到客户信息集合43 /// </summary>44 /// <param name="where">条件</param>45 /// <returns>客户信息集合</returns>46 public IList<Customer> GetCustomerList(Expression<Func<Customer, bool>> where)47 {48 try49 {50 NHibernateHelper nhibernateHelper = new NHibernateHelper();51 ISession session = nhibernateHelper.GetSession();52 return session.Query<Customer>().Where(where).ToList();53 }54 catch (Exception ex)55 {56 throw ex;57 }58 }59 }60 }
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Linq.Expressions; 5 using System.Text; 6 using System.Threading.Tasks; 7 using Wolfy.Shop.Data; 8 using Wolfy.Shop.Domain.Entities; 9 10 namespace Wolfy.Shop.Business11 {12 13 /// <summary>14 /// 描述:客户信息业务逻辑层15 /// 创建人:wolfy16 /// 创建时间:2014-10-1717 /// </summary>18 public class CustomerBusiness19 {20 private CustomerData _customerData;21 public CustomerBusiness()22 {23 _customerData = http://www.mamicode.com/new CustomerData();24 }25 /// <summary>26 /// 添加客户27 /// </summary>28 /// <param name="customer">客户实体</param>29 /// <returns>是否添加成功 </returns>30 public bool AddCustomer(Customer customer)31 {32 return _customerData.AddCustomer(customer);33 }34 /// <summary>35 /// 根据条件得到客户信息集合36 /// </summary>37 /// <param name="where">条件</param>38 /// <returns>客户信息集合</returns>39 public IList<Customer> GetCustomerList(Expression<Func<Customer, bool>> where)40 {41 return _customerData.GetCustomerList(where);42 }43 }44 }
测试
为了以后使用方便,在这里使用webform项目作为测试,通过单击“添加”按钮,向数据库中插入记录,
页面
1 <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="CustomerManager.aspx.cs" Inherits="Wolfy.Shop.WebSite.CustomerManager" %> 2 3 <!DOCTYPE html> 4 5 <html xmlns="http://www.w3.org/1999/xhtml"> 6 <head runat="server"> 7 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 8 <title></title> 9 <style type="text/css">10 .main {11 border: 1px solid #0094ff;12 margin: 50px auto;13 width: 600px;14 }15 16 .table {17 border: 1px solid #0094ff;18 border-collapse: collapse;19 width: 98%;20 text-align: center;21 margin:5px auto;22 }23 24 .table th {25 background-color: lightgray;26 }27 .table tr td {28 border: 1px solid #0094ff;29 }30 </style>31 </head>32 <body>33 <form id="form1" runat="server">34 <div class="main">35 <asp:Button runat="server" ID="btnAdd" Text="添加" OnClick="btnAdd_Click" />36 <div>37 <asp:Repeater runat="server" ID="rptCustomerList">38 <HeaderTemplate>39 <table class="table">40 <tr>41 <th>姓名</th>42 <th>姓名</th>43 <th>地址</th>44 </tr>45 </HeaderTemplate>46 <ItemTemplate>47 <tr>48 <td><%#Container.ItemIndex+1 %></td>49 <td><%#Eval("CustomerName") %></td>50 <td><%#Eval("CustomerAddress") %></td>51 </tr>52 </ItemTemplate>53 <FooterTemplate>54 </table>55 </FooterTemplate>56 </asp:Repeater>57 </div>58 </div>59 </form>60 </body>61 </html>
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Web; 5 using System.Web.UI; 6 using System.Web.UI.WebControls; 7 using Wolfy.Shop.Domain.Entities; 8 9 namespace Wolfy.Shop.WebSite10 {11 public partial class CustomerManager : System.Web.UI.Page12 {13 protected void Page_Load(object sender, EventArgs e)14 {15 if (!IsPostBack)16 {17 RepeaterDataBind();18 }19 }20 private void RepeaterDataBind()21 {22 Business.CustomerBusiness customerBusiness = new Business.CustomerBusiness();23 this.rptCustomerList.DataSource = customerBusiness.GetCustomerList(c => 1 == 1);24 this.rptCustomerList.DataBind();25 }26 /// <summary>27 /// 添加客户信息28 /// </summary>29 /// <param name="sender"></param>30 /// <param name="e"></param>31 protected void btnAdd_Click(object sender, EventArgs e)32 {33 var customer = new Customer() { CustomerName = "wolfy", CustomerAddress = "北京 海淀", CustomerID = Guid.NewGuid() };34 Business.CustomerBusiness customerBusiness = new Business.CustomerBusiness();35 if (customerBusiness.AddCustomer(customer))36 {37 this.RepeaterDataBind();38 }39 }40 }41 }
界面
通过SQL Server Profiler查看生成的sql语句
通过监控到的sql语句,也可以看到使用nhibernate插入数据时,数据库中是通过存储过程进行插入数据的。
总结
本文简单介绍了使用nhibernate的一些配置,给我的感觉是,在使用时只要配置正确,其他的增删改查什么的也就没什么难的了。在配置nhibernate的时候,有些细节需要注意。比如映射文件和nhibernate的配置文件的属性需要进行修改。
参考文章
http://www.cnblogs.com/lyj/archive/2008/10/14/1310913.html#comment_tip
[NHibernate]基本配置与测试