欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

在C#项目中如何使用NHibernate详解

程序员文章站 2023-12-16 10:39:46
前言 现代化大型项目通常使用独立的数据库来存储数据,其中以采用关系型数据库居多。用于开发项目的高级语言(c#、java等)是面向对象的,而关系型数据库是基于关系的,两者之...

前言

现代化大型项目通常使用独立的数据库来存储数据,其中以采用关系型数据库居多。用于开发项目的高级语言(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,位于数据访问层工具类库)

 在C#项目中如何使用NHibernate详解

 图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

using system;
using fuli.tool.log;
using nhibernate;
using nhibernate.cfg;
namespace fuli.dal.common
{
 public class nhibernatehelper
 {
 private static isessionfactory _sessionfactory;
 private static isessionfactory sessionfactory
 {
  get
  {
  if (_sessionfactory == null)
  {
   var configuration = new configuration();
   configuration.configure();
   _sessionfactory = configuration.buildsessionfactory();
  }
  return _sessionfactory;
  }
 }

 public static isession opensession()
 {
  try
  {
  return sessionfactory.opensession();
  }
  catch (exception ex)
  {
  loghelper.getinstance().writemessage("打开数据库失败,错误:" + ex.tostring());
  return null;
  }
 }
 }
}

5. 创建数据模型

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

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

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

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

using system;
using system.collections.generic;

namespace fuli.entity.domain
{
 /// <summary>
 /// 共享编码表(字典表)
 /// </summary>
 [serializable]
 public class sharedcode
 {
 #region 构造方法

 public sharedcode()
 {
  m_id = 0;
  m_category = string.empty;
  m_text = string.empty;
  m_value = string.empty;
  m_isdefault = false;
  m_description = string.empty;
  m_parentid = 0;
  m_sortorder = 0;
 }

 #endregion 构造方法

 #region 私有变量

 private long m_id;
 private string m_category;
 private string m_text;
 private string m_value;
 private bool m_isdefault;
 private string m_description;
 private long m_parentid;
 private short m_sortorder;

 #endregion 私有变量

 #region 公有属性

 ///<summary>
 /// 主键id
 ///</summary>
 public virtual long id
 {
  get { return m_id; }
  set { m_id = value; }
 }

 ///<summary>
 /// 分类
 ///</summary>
 public virtual string category
 {
  get { return m_category; }
  set { m_category = value; }
 }

 ///<summary>
 /// 文本
 ///</summary>
 public virtual string text
 {
  get { return m_text; }
  set { m_text = value; }
 }

 ///<summary>
 /// 编码值
 ///</summary>
 public virtual string value
 {
  get { return m_value; }
  set { m_value = value; }
 }

 ///<summary>
 /// 是否是同类里默认
 ///</summary>
 public virtual bool isdefault
 {
  get { return m_isdefault; }
  set { m_isdefault = value; }
 }

 ///<summary>
 /// 描述
 ///</summary>
 public virtual string description
 {
  get { return m_description; }
  set { m_description = value; }
 }

 ///<summary>
 /// 父级id(如果有)
 ///</summary>
 public virtual long parentid
 {
  get { return m_parentid; }
  set { m_parentid = value; }
 }

 ///<summary>
 /// 排列次序
 ///</summary>
 public virtual short sortorder
 {
  get { return m_sortorder; }
  set { m_sortorder = value; }
 }

 #endregion 公有属性

 #region 扩展属性

 #endregion 扩展属性

 #region rewrite equals and hashcode

 /// <summary>
 /// 
 /// </summary>
 public override bool equals(object obj)
 {
  if(this == obj) return true;
  if((obj == null) || (obj.gettype() != gettype())) return false;
  sharedcode castobj = (sharedcode)obj;
  return (castobj != null) && (m_id == castobj.id);
 }

 /// <summary>
 /// 用唯一值实现gethashcode
 /// </summary>
 public override int gethashcode()
 {
  int hash = 57;
  hash = 27 * hash * m_id.gethashcode();
  return hash;
 }

 #endregion rewrite equals and hashcode
 }
}

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文件,那么映射就不会生效了。

 在C#项目中如何使用NHibernate详解

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

7. 使用 nhibernate连接数据库

文件:commonrepository

namespace fuli.dal.sqlserverimpl
{
 public class commonrepository : icommonrepository
 {
  #region 新增
  /// <summary>
  /// 新增实体表
  /// </summary>
  /// <param name="obj"></param>
  /// <returns></returns>
  public long addnewentity<t>(object obj, string tablename) where t : new()
  {
   long id = 0;
   try
   {
    using (isession session = nhibernatehelper.opensession())
    {
     id = long.parse(session.save((t)obj).tostring());
     session.flush();
    }
   }
   catch (exception ex)
   {
    loghelper.getinstance().writemessage(tablename + operationtype.comma + ex.tostring());
   }
   return id;
  }

  /// <summary>
  /// 新增实体表
  /// </summary>
  /// <param name="entity"></param>
  /// <returns></returns>
  public treturn addnewentity<tentity, treturn>(object entity, string tablename) where tentity : new()
  {
   treturn returnvalue = default(treturn);
   try
   {
    using (isession session = nhibernatehelper.opensession())
    {
     object returnobject = session.save(entity);
     if (returnobject != null)
     {
      returnvalue = (treturn)convert.changetype(returnobject, typeof(treturn));
     }
     session.flush();
    }
   }
   catch (exception ex)
   {
    loghelper.getinstance().writemessage(tablename + operationtype.comma + ex.tostring());
   }
   return returnvalue;
  }
  #endregion 新增
 }
}

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

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对的支持。

上一篇:

下一篇: