惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
爱范儿
爱范儿
H
Help Net Security
V
Visual Studio Blog
J
Java Code Geeks
Stack Overflow Blog
Stack Overflow Blog
Microsoft Security Blog
Microsoft Security Blog
Apple Machine Learning Research
Apple Machine Learning Research
MyScale Blog
MyScale Blog
The Cloudflare Blog
Martin Fowler
Martin Fowler
D
Docker
腾讯CDC
F
Fortinet All Blogs
雷峰网
雷峰网
GbyAI
GbyAI
G
Google Developers Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Recent Announcements
Recent Announcements
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Blog — PlanetScale
Blog — PlanetScale
Engineering at Meta
Engineering at Meta
博客园 - 聂微东
博客园 - 叶小钗

博客园 - 灵动生活

重磅出击!!春季小程序活动大作战,看我怎么玩?? 面向对象之六大设计原则 微信小程序基于腾讯云对象存储的图片上传 外卖小程序对接飞鹅小票打印的实现 微信小程序大型系统架构中应用Redis缓存要点 微信小程序如何实现自动退款功能? 从“跳一跳”来看微信小程序的未来 为你揭露2018微信公开课pro的12个重点 酷客多小程序受邀参加 中国县域连锁药店发展峰会 促进客户转化,提高客单价!酷客多小程序发布版本V1.0.9! 重磅消息:微信小程序支持长按二维码进入 「酷客多」关注:马化腾公开演讲,透露2017年春节前会推出“小程序” 微信小程序购物商城系统开发系列-目录结构 微信小程序购物商城系统开发系列-工具篇 上海闪酷成为京东商城第一批独立软件开发商(ISV) 创业邦杂志报道上海闪酷:传统企业进军电商,IT系统问题怎么解决?这家企业或许可以帮到你 Fatal error: Call to undefined function session_start() asp.net Jquery图片延迟加载 TFS2010合并与分支(Branch and Merge)
如何在C#项目中使用NHibernate
灵动生活 · 2018-03-28 · via 博客园 - 灵动生活

现代化大型项目通常使用独立的数据库来存储数据,其中以采用关系型数据库居多。用于开发项目的高级语言(C#、Java等)是面向对象的,而关系型数据库是基于关系的,两者之间的沟通需要一种转换,也就是对象/关系数据库映射(Object/Relational Mapping,简称ORM)。

C#可用以解决对象/关系数据库映射的工具有多种,常见的有EF (Entity Framework)、NHibernate、iBATIS等,各自的优缺点及适用场景在此不做讨论,本文只对如何使用NHibernate做个总结。

NHibernate是一个面向.NET环境的对象/关系数据库映射工具。

1. 创建项目文件

在Visual Studio开发工具里创建需要的项目结构。

2. 添加对NHibernate的引用

当下载并解压NHibernate安装包后,电脑上就会创建一些目录,包括“Required_Bins”,要把 Required_Bins目录下的DLL引用到项目里来,它们是NHibernate使用的核心组件。

NHibernate.dll(基础类库,与数据库直接打交道,位于数据访问层)

Iesi.Collections(基础类库辅助类库,位于数据访问层)

Antlr3.Runtime(基础类库辅助类库,位于数据访问层)

NHibernate.ByteCode.Spring.dll(Proxy Factory类库,用于打开/关闭Nhibernate Session,位于数据访问层工具类库)

 

                                       图1 添加对NHibernate的引用

3. 配置NHibernate

文件:hibernate.cfg.xml,位于站点根目录

<?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">
        Data Source=120.120.200.200;Initial Catalog=MAMall;Persist Security Info=True;User ID=mamall;Password=mima123;connection reset=false;connection lifetime=50;min pool size=1;max pool size=500
    </property>
    <property name="adonet.batch_size">10</property>
    <property name="show_sql">true</property>
    <property name="dialect">NHibernate.Dialect.MsSql2005Dialect</property>
    <property name="command_timeout">10</property>
    <property name="query.substitutions">true 1, false 0, yes 'Y', no 'N'</property>
    <property name="proxyfactory.factory_class"> NHibernate.ByteCode.Spring.ProxyFactoryFactory,NHibernate.ByteCode.Spring</property>
    <property name="connection.release_mode">on_close</property>
    <mapping assembly="Fuli.Entity"/>
  </session-factory>
</hibernate-configuration>

4. 编写NHibernateHelper辅助类

文件:NHibernateHelper.cs

 1 using System;
 2 using Fuli.Tool.Log;
 3 using NHibernate;
 4 using NHibernate.Cfg;
 5 
 6 namespace Fuli.DAL.Common
 7 {
 8     public class NHibernateHelper
 9     {
10         private static ISessionFactory _sessionFactory;
11         private static ISessionFactory SessionFactory
12         {
13             get
14             {
15                 if (_sessionFactory == null)
16                 {
17                     var configuration = new Configuration();
18                     configuration.Configure();
19                     _sessionFactory = configuration.BuildSessionFactory();
20                 }
21                 return _sessionFactory;
22             }
23         }
24 
25         public static ISession OpenSession()
26         {
27             try
28             {
29                 return SessionFactory.OpenSession();
30             }
31             catch (Exception ex)
32             {
33                 LogHelper.GetInstance().WriteMessage("打开数据库失败,错误:" + ex.ToString());
34                 return null;
35             }
36         }
37     }
38 }

5. 创建数据模型

NHibernate允许直接使用Plain Old CLR Objects (POCOs),而不用通过存储过程来直接和数据库交互。使用POCOs的一个优势在于不用绑定特定的持久化层。相比较而言,有些ORM解决方案需要特殊属性,或者是基于模型对象,这些对象又是从特定的基类中继承而来的。

在NHibernate中不用特殊的修饰就可以让对象和持久化层交互。要注意的是所有需要持久化的属性必须是虚拟的,并且要开启延迟加载,所有数据模型类中的公共方法必须是虚拟的,哪怕它们并没有包含到映射文件中。

通常来讲,最好把所有的属性都设置为虚拟的。

可以借助MyGeneration自动代码工具从数据表生成数据模型和对应的映射文件。

  1 using System;
  2 using System.Collections.Generic;
  3 
  4 namespace Fuli.Entity.Domain
  5 {
  6     /// <summary>
  7     /// 共享编码表(字典表)
  8     /// </summary>
  9     [Serializable]
 10     public class SharedCode
 11     {
 12         #region 构造方法
 13 
 14         public SharedCode()
 15         {
 16             m_Id = 0;
 17             m_Category = string.Empty;
 18             m_Text = string.Empty;
 19             m_Value = string.Empty;
 20             m_IsDefault = false;
 21             m_Description = string.Empty;
 22             m_ParentId = 0;
 23             m_SortOrder = 0;
 24         }
 25 
 26         #endregion 构造方法
 27 
 28         #region 私有变量
 29 
 30         private long m_Id;
 31         private string m_Category;
 32         private string m_Text;
 33         private string m_Value;
 34         private bool m_IsDefault;
 35         private string m_Description;
 36         private long m_ParentId;
 37         private short m_SortOrder;
 38 
 39         #endregion 私有变量
 40 
 41         #region 公有属性
 42 
 43         ///<summary>
 44         /// 主键Id
 45         ///</summary>
 46         public virtual long Id
 47         {
 48             get { return m_Id; }
 49             set { m_Id = value; }
 50         }
 51 
 52         ///<summary>
 53         /// 分类
 54         ///</summary>
 55         public virtual string Category
 56         {
 57             get { return m_Category; }
 58             set { m_Category = value; }
 59         }
 60 
 61         ///<summary>
 62         /// 文本
 63         ///</summary>
 64         public virtual string Text
 65         {
 66             get { return m_Text; }
 67             set { m_Text = value; }
 68         }
 69 
 70         ///<summary>
 71         /// 编码值
 72         ///</summary>
 73         public virtual string Value
 74         {
 75             get { return m_Value; }
 76             set { m_Value = value; }
 77         }
 78 
 79         ///<summary>
 80         /// 是否是同类里默认
 81         ///</summary>
 82         public virtual bool IsDefault
 83         {
 84             get { return m_IsDefault; }
 85             set { m_IsDefault = value; }
 86         }
 87 
 88         ///<summary>
 89         /// 描述
 90         ///</summary>
 91         public virtual string Description
 92         {
 93             get { return m_Description; }
 94             set { m_Description = value; }
 95         }
 96 
 97         ///<summary>
 98         /// 父级Id(如果有)
 99         ///</summary>
100         public virtual long ParentId
101         {
102             get { return m_ParentId; }
103             set { m_ParentId = value; }
104         }
105 
106         ///<summary>
107         /// 排列次序
108         ///</summary>
109         public virtual short SortOrder
110         {
111             get { return m_SortOrder; }
112             set { m_SortOrder = value; }
113         }
114 
115         #endregion 公有属性
116 
117         #region 扩展属性
118 
119         #endregion 扩展属性
120 
121         #region Rewrite Equals and HashCode
122 
123         /// <summary>
124         /// 
125         /// </summary>
126         public override bool Equals(object obj)
127         {
128             if(this == obj) return true;
129             if((obj == null) || (obj.GetType() != GetType())) return false;
130             SharedCode castObj = (SharedCode)obj;
131             return (castObj != null) && (m_Id == castObj.Id);
132         }
133 
134         /// <summary>
135         /// 用唯一值实现GetHashCode
136         /// </summary>
137         public override int GetHashCode()
138         {
139             int hash = 57;
140             hash = 27 * hash * m_Id.GetHashCode();
141             return hash;
142         }
143 
144         #endregion Rewrite Equals and HashCode
145     }
146 }

6. 创建NHibernate映射文件

Nhibernate使用XML映射文件来映射POCO到数据库对象。虽然在很多案例中这可能是一对一关系,但这并不是必定的。

文件:SharedCode.hbm.xml

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
    <class name="Fuli.Entity.Domain.SharedCode, Fuli.Entity" table="SharedCode">
        <id name="Id" column="Id" type="Int64" unsaved-value="0">
            <generator class="native"/>
        </id>
        <property name="Category" type="String" column="Category"/>
        <property name="Text" type="String" column="Text"/>
        <property name="Value" type="String" column="Value"/>
        <property name="IsDefault" type="Boolean" column="IsDefault"/>
        <property name="Description" type="String" column="Description"/>
        <property name="ParentId" type="Int64" column="ParentId"/>
        <property name="SortOrder" type="Int16" column="SortOrder"/>
    </class>
</hibernate-mapping>

在hibernate-maping标签中,同时引用类集(POCOs)所属的程序集命名空间。

  • class元素表示到单个POCO的映射。name表示上面的程序集和命名空间中的类名,table属性告诉NHibernate数据库中的哪个表或者视图将被映射。
  • id元素告诉NHibernate哪个数据库的字段和对应的对象作为一个唯一键来使用。在本例中,我们使用Id这个字段。
  • generator元素告诉NHibernate怎样给新实体来创建唯一ID。
  • property标签是见得最多的标签。它简单地映射一个到数据表或者视图中对应字段的映射。

一旦XML文件创建好了,需要更改XML的生成方式确保它被设置为嵌入式资源,否则NHibernate不会读取这个XML文件,那么映射就不会生效了。

 

          图2 映射文件必须是嵌入的资源

7. 使用 NHibernate连接数据库

文件:CommonRepository

 1 namespace Fuli.DAL.SQLServerImpl
 2 {
 3     public class CommonRepository : ICommonRepository
 4     {
 5         #region 新增
 6 
 7         /// <summary>
 8         /// 新增实体表
 9         /// </summary>
10         /// <param name="obj"></param>
11         /// <returns></returns>
12         public long AddNewEntity<T>(object obj, string tableName) where T : new()
13         {
14             long id = 0;
15             try
16             {
17                 using (ISession session = NHibernateHelper.OpenSession())
18                 {
19                     id = long.Parse(session.Save((T)obj).ToString());
20                     session.Flush();
21                 }
22             }
23             catch (Exception ex)
24             {
25                 LogHelper.GetInstance().WriteMessage(tableName + OperationType.COMMA + ex.ToString());
26             }
27             return id;
28         }
29 
30         /// <summary>
31         /// 新增实体表
32         /// </summary>
33         /// <param name="entity"></param>
34         /// <returns></returns>
35         public TReturn AddNewEntity<TEntity, TReturn>(object entity, string tableName) where TEntity : new()
36         {
37             TReturn returnValue = default(TReturn);
38             try
39             {
40                 using (ISession session = NHibernateHelper.OpenSession())
41                 {
42                     object returnObject = session.Save(entity);
43                     if (returnObject != null)
44                     {
45                         returnValue = (TReturn)Convert.ChangeType(returnObject, typeof(TReturn));
46                     }
47                     session.Flush();
48                 }
49             }
50             catch (Exception ex)
51             {
52                 LogHelper.GetInstance().WriteMessage(tableName + OperationType.COMMA + ex.ToString());
53             }
54 
55             return returnValue;
56         }
57 
58         #endregion 新增
59     }
60 }

对于不同的实体,可以一对一地写一个<Entity>Repository,专注负责相对应的实体操作。

8. 附录

NHibernate开源项目:https://sourceforge.net/projects/nhibernate/files/NHibernate/

Your first NHibernate based application:http://nhibernate.info/doc/tutorials/first-nh-app/your-first-nhibernate-based-application.html

NHibernate 快速上手:http://www.oschina.net/translate/nhibernate-quickstart?p=1#comments

Quickstart with NHibernate:https://docs.google.com/document/d/1OTC16N1GnKvgkIDvQn_RkQS_y3vvjYav-Ons9JLEUCU/edit?pli=1

NHibernate词条:https://baike.baidu.com/item/NHibernate

ANTLR:http://www.antlr.org/

酷客多小程序  陈苏