.NET 常用ORM之NHibernate
NHibernate做.Net应该都不陌生,今天我们就算是温故下这个技术,概念性的东西就不说了,这次主要说本人在实际使用的遇到的问题,比较费解现在就当是记录下,避免以后再犯。本次主要使用的情况是1对N多表关联操作,具体情况如下(给出主要代码):
一、NHibernate配置
(1) 引入动态库
Antlr3.Runtime.dll、NHibernate.dll、Newtonsoft.Json.dll、Iesi.Collections.dll相关动态库,用NuGet导入即可
(2)配置文件
configSections加入NHibernate配置信息
- <configSections>
- <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
- <section name="hibernate-configuration" type="NHibernate.Cfg.ConfigurationSectionHandler, NHibernate" />
- <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
- </configSections>
Nhibernate相关配置信息及数据链接配置
- <hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
- <session-factory name="Sys.Dal">
- <property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
- <property name="connection.connection_string">Data Source=.;Initial Catalog=AttendanceDB;User ID=sa;Password=******;</property>
- <property name="show_sql">false</property>
- <property name="query.substitutions">true , false , yes 'Y', no 'N'</property>
- <property name="dialect">NHibernate.Dialect.MsSql2012Dialect</property>
- <property name="proxyfactory.factory_class">NHibernate.Bytecode.DefaultProxyFactoryFactory, NHibernate</property>
- <property name="hbm2ddl.keywords">none</property>
- <mapping assembly="Sys.Model" />
- </session-factory>
- </hibernate-configuration>
(3)创建创建session工场,方便后面直接使用
- public class SessionManager
- {
- private static Configuration _cfg = new Configuration().AddAssembly("Sys.Model");
- private static ISessionFactory _sessionFactory = _cfg.BuildSessionFactory();
- private SessionManager()
- {
- }
- public static ISession GetSession()
- {
- return _sessionFactory.OpenSession();
- }
- public static IStatelessSession GetStateLessSession()
- {
- return _sessionFactory.OpenStatelessSession();
- }
- }
二、实际使用
(1)相关实体和映射文件
User.cs
- public class User
- {
- public virtual int ID { get; set; }
- public virtual string UserName { get; set; }
- public virtual string UserPwd { get; set; }
- public virtual int UserType { get; set; }
- public virtual string Telephone { get; set; }
- public virtual string CreateDate { get; set; }
- public virtual string UpdateDate { get; set; }
- public virtual int Status { get; set; }
- public virtual string Remark { get; set; }
- public virtual ISet<AttendanceInfo> listAttendanceInfo { get; set; }
- }
- <?xml version="1.0" encoding="utf-8" ?>
- <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
- <class name="Sys.Model.User, Sys.Model" table="Tb_User" lazy="true">
- <id name="ID" column="ID" type="Int32">
- <generator class="identity" />
- </id>
- <property name="UserName" type="String">
- <column name="UserName"/>
- </property>
- <property name="UserPwd" type="String">
- <column name="UserPwd"/>
- </property>
- <property name="UserType" type="Int32">
- <column name="UserType"/>
- </property>
- <property name="Telephone" type="String">
- <column name="Telephone"/>
- </property>
- <property name="CreateDate" type="String">
- <column name="CreateDate"/>
- </property>
- <property name="UpdateDate" type="String">
- <column name="UpdateDate"/>
- </property>
- <property name="Status" type="Int32">
- <column name="Status"/>
- </property>
- <property name="Remark" type="String">
- <column name="Remark"/>
- </property>
- <!-- 一个User有多个Attendance -->
- <set name="listAttendanceInfo" table="Tb_AttendanceInfo" generic="true" inverse="true" >
- <key column="ID" foreign-key="FK_Att_User"/>
- <one-to-many class="Sys.Model.AttendanceInfo, Sys.Model"/>
- </set>
- </class>
- </hibernate-mapping>
- AttendanceInfo.cs
- public class AttendanceInfo
- {
- public virtual int ID { get; set; }
- public virtual int UID { get; set; }
- public virtual string CheckInTime { get; set; }
- public virtual string CheckOutTime { get; set; }
- public virtual int Status { get; set; }
- public virtual int ConfirmUID { get; set; }
- public virtual string ConfirmTime { get; set; }
- public virtual string Remark { get; set; }
- public virtual User UserInfo { get; set; }
- }
- <?xml version="1.0" encoding="utf-8" ?>
- <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
- <class name="Sys.Model.AttendanceInfo, Sys.Model" table="Tb_AttendanceInfo" lazy="true">
- <id name="ID" column="ID" type="Int32">
- <generator class="identity" />
- </id>
- <property name="UID" type="Int32">
- <column name="UID"/>
- </property>
- <property name="CheckInTime" type="String">
- <column name="CheckInTime"/>
- </property>
- <property name="CheckOutTime" type="String">
- <column name="CheckOutTime"/>
- </property>
- <property name="Status" type="Int32">
- <column name="Status"/>
- </property>
- <property name="ConfirmUID" type="Int32">
- <column name="ConfirmUID"/>
- </property>
- <property name="ConfirmTime" type="String">
- <column name="ConfirmTime"/>
- </property>
- <property name="Remark" type="String">
- <column name="Remark"/>
- </property>
- <many-to-one name="UserInfo" column="UID" not-null="true" class="Sys.Model.User, Sys.Model" foreign-key="FK_Att_User" />
- </class>
- </hibernate-mapping>
(2)获取数据——原意是获取AttendanceInfo带出User上面的个别字段
- public List<AttendanceInfo> GetAttendanceInfoByWhere(string uname)
- {
- using (ISession session = SessionManager.GetSession())
- {
- ICriteria criteria = session.CreateCriteria<AttendanceInfo>();
- List<AttendanceInfo> lsAtt = criteria.List<AttendanceInfo>().ToList();
- return lsAtt;
- }
- }
调用方法:
- public JsonResult GetUserAttInfo()
- {
- if (Session["uid"] != null && Session["uType"] != null)
- {
- string strWhe = Request["strWhe"].ToString();
- Bll_AttendanceInfo bllAtt = new Bll_AttendanceInfo();
- string uname = string.Empty;
- if (Session["uType"].ToString().Equals(""))
- uname = Session["uname"].ToString();
- else
- uname = strWhe;
- List<AttendanceInfo> lsAtt = bllAtt.GetAttendanceInfoByWhere(uname);
- if (lsAtt != null && lsAtt.Count > )
- {
- return Json(JsonHeleper.ObjectToJSON(lsAtt));
- }
- return Json("{\"respCode\":\"faile\",\"respMsg\":\"未获取到任何行,请稍后重试!\"}");
- }
- else
- {
- return Json("{\"respCode\":\"faile\",\"respMsg\":\"Session丢失,请稍后重试!\"}");
- }
- }
- public static string ObjectToJSON<T>(T obj)
- {
- return JsonConvert.SerializeObject(obj);
- }
好,到这里看上去配置映射关系好像没多大问题,但是实际上问题就出来了
问题一:在调用的GetAttendanceInfoByWhere的时候会出现:no session or session was closed...
其实是因为做了映射关系先去子表在去主表数据,session释放掉了;需要在子表的映射文件加上个lazy="false",把延迟加载关掉使用使用代理延迟,那么这个问题解决了。
上面的问题是在去取值的时候会抛出异常,接着问题又来了,问题二:Json(JsonHeleper.ObjectToJSON(lsAtt))也就是到最后的JsonConvert.SerializeObject(obj),json序列化出错,怎么可能系统紫的json序列化方法会出错,而且这里报的错和上面的那个错误信息基本一致,字面意思也是session不存在或者关掉,纳闷,刚刚明明已经处理掉这个问题,为毛在取值的地方没出现,在返回的json序列化出错,找了很久其实有时映射文件配置问题,在主表也就是User的映射文件中加上了cascade="all" generic="true",以及在子表映射文件加上 not-found= "ignore" ,就ok了
紧接着第三个问题,还是在返回json序列化的时候异常:Self referencing loop detected for property 'ParentClassify' with type...字面意思就是自引用循环,就是主类新加子类的属性到实体,子类新增主类的属性到实体,就出了这种问题,怎么解决?调整了下最终的对象转json的方法ObjectToJSON,需要导入包文件
- using Newtonsoft.Json;
- public static string ObjectToJSON<T>(T obj)
- {
- //return JsonConvert.SerializeObject(obj);
- JsonSerializerSettings settings = new JsonSerializerSettings();
- settings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
- return JsonConvert.SerializeObject(obj, settings);
- }
到此为止,关联查询算是没问题了,但是不要庆幸,这只是查询,接下来做了下子表的新增和修改操作,结果让人奔溃,异常!!!!!!
错误信息:Error dehydrating property value for...
最终导致这个问题是因为数据库字段和映射文件字段不一致,对应不起来,因为映射文件加了个关联对象。需要在加的关联对象的hbm.xml文件里面加上insert="false" update="false",让新增和修改的时候忽略掉。开发工具却一直报但是它一直抛Error dehydrating property value for...误导排错方向,这个坑,让人无语。
最后顺便提一嘴,在使用Nhibernate多表关联的时候,mapping配置还真的小心点,一不小心就是个坑,而且资料不是很好找。
最终两个hbm.xml的关联关系配置变成如下:
User.hbm.xml
- <!-- 一个User有多个Attendance -->
- <set name="listAttendanceInfo" table="Tb_AttendanceInfo" cascade="all" generic="true" inverse="true" lazy="false" >
- <key column="ID" foreign-key="FK_Att_User" not-null="false"/>
- <one-to-many class="Sys.Model.AttendanceInfo, Sys.Model" not-found= "ignore" />
- </set>
AttendanceInfo.hbm.xml
- <many-to-one name="UserInfo" column="UID" not-null="false" class="Sys.Model.User, Sys.Model" cascade="none" not-found="ignore" insert="false" update="false" foreign-key="FK_Att_User" />
到此几个坑基本解决,表示很心累。写出来也后来遇到的人参考,有何不对的地方也欢迎大家指教。
(另外,需要注意的是建立one-to-many或者many-to-on的栏位需要是主键,所以需要留意xml映射文件的书写)
三、关联表配置的映射属性
上面也提到了,好几个问题都是在做关联关系配置的时候出的问题,顺便附上关联表配置的映射属性拱参考
- access(默认property):可选field、property、nosetter、ClassName值。NHibernate访问属性的策略。
- cascade(可选):指明哪些操作会从父对象级联到关联的对象。可选all、save-update、delete、none值。除none之外其它将使指定的操作延伸到关联的(子)对象。
- class(默认通过反射得到属性类型):关联类的名字。
- column(默认属性名):列名。
- fetch(默认select):可选select和join值,select:用单独的查询抓取关联;join:总是用外连接抓取关联。
- foreign-key:外键名称,使用SchemaExport工具生成的名称。
- index:......
- update,insert(默认true):指定对应的字段是否包含在用于UPDATE或INSERT 的SQL语句中。如果二者都是false,则这是一个纯粹的 “外源性(derived)”关联,它的值是通过映射到同一个(或多个)字段的某些其他特性得到或者通过触发器其他程序得到。
- lazy:可选false和proxy值。是否延迟,不延迟还是使用代理延迟。
- name:属性名称propertyName。
- not-found:可选ignore和exception值。找不到忽略或者抛出异常。
- not-null:可选true和false值。
- outer-join:可选auto、true、false值。
- property-ref(可选):指定关联类的一个属性名称,这个属性会和外键相对应。如果没有指定,会使用对方关联类的主键。这个属性通常在遗留的数据库系统使用,可能有外键指向对方关联表的某个非主键字段(但是应该是一个唯一关键字)的情况下,是非常不好的关系模型。比如说,假设Customer类有唯一的CustomerId,它并不是主键。这一点在NHibernate源码中有了充分的体验。
- unique:可选true和false值。控制NHibernate通过SchemaExport工具生成DDL的过程。
- unique-key(可选):使用DDL为外键字段生成一个唯一约束。
.NET 常用ORM之NHibernate的更多相关文章
- ORM概述及常用ORM框架
一.ORM ORM(Object-relational mapping),即对象关系映射,是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术.也就是说,ORM是通过使用描述对象和数据库之间映 ...
- Nhibernate系列学习之(一) ORM and Nhibernate入门实例解析
最近框架项目需要,数据层想使用Nhibernate,代替传统的sql语句的写法,更加使用面向对象的思维来维护实体与数据库的这层关系映射(ORM),好在之前接触过Java时学习使用了Hibernate, ...
- .NET 常用ORM之SubSonic
一.SubSonic简单介绍 SubSonic是一个类似Rails的开源.NET项目.你可以把它看作是一把瑞士军刀,它可以用来构建Website和通过ORM方式来访问数据.Rob Conery和Eri ...
- .NET 常用ORM之iBatis
ibatis 一词来源于“internet”和“abatis”的组合,是一个由Clinton Begin在2001年发起的开放源代码项目,到后面发展的版本叫MyBatis但都是指的同一个东西.最初侧重 ...
- .NET 常用ORM之Gentle.Net
.Net常用的就是微软的EF框架和Nhibernate,这两个框架用的都比较多就不做详细介绍了,今天我们来看看Gentle.Net,Gentle.Net是一个开源的优秀O/R Mapping的对象持久 ...
- .Net 常用ORM框架对比:EF Core、FreeSql、SqlSuger
前言: 最近由于工作需要,需要选用一种ORM框架,也因此对EF Core.FreeSql.SqlSuger作简单对比.个人认为各有有优势,存在即合理,不然早就被淘汰了是吧,所以如何选择因人而议.因项目 ...
- .NET 常用ORM之Nbear
NBear是一个基于.Net 2.0.C#2.0开放全部源代码的的软件开发框架类库.NBear的设计目标是尽最大努力减少开发人员的工作量,最大程度提升开发效率,同时兼顾性能及可伸缩性. 一.新建项目并 ...
- yii 常用orm
yii2 orwhere andwhere的复杂写法:https://www.codercto.com/a/6513.html $files = XXXX::find() ->andWhere( ...
- [Nhibernate]体系结构
引言 在项目中也有用到过nhibernate但对nhibernate的认识,也存留在会用的阶段,从没深入的学习过,决定对nhibernate做一个系统的学习. ORM 对象-关系映射(OBJECT/R ...
随机推荐
- react中constructor()和super()的具体含义以及如何使用
1.constructor()---super( )的基本含义 constructor()--构造方法 这是ES6对类的默认方法,通过new命令生成对象实例时自动调用该方法.并且,该方法是类中必须有的 ...
- java文件与流课后作业
1,编写一个程序,指定一个文件夹,能自动计算出其总容量, 2,编写一个文件加解密程序,通过命令行完成加解密工作3,编写一个文件分割工具,能把一个大文件分割成多个小的文件.并且能再次把它们合并起来得到完 ...
- js高级1
1.每一个元素身上的事件都是天生自带的,不需要我们去定义,只需要我们给这个事件绑定的方法,当事件触发的时候就会执行这个方法. 2.事件绑定的方法 1,div.onclick=function(){} ...
- Source Insight4
创建工程: File->open 打开创建的工程 同步文件: 方便跟踪 Project->Synchronize Files 打开小窗口 ...
- new image()
在js中 新建一个new image()对象,image.src图片地址,这个是io读取是异步的,解决方法 image.onload=function(){ }
- JS操作字符串
JS操作字符串 1.函数:split() 把字符串按分隔符分割成数组. 语法:字符串.split(separator,limit); separator:分隔符. 功能:使用一个指定的分隔符把一个字符 ...
- 中国省份毗邻关系JSON数据[相邻省份][所辖市级信息][行政区划]
最近做一个需求, 需要一份每个省份相邻[毗邻]的省份信息,这里整理了一版. json 数据,结构大致这样子的. [ { "id": 7, "name": &qu ...
- Fiddler_菜单栏介绍_02
Fiddler界面 [Statistics]请求的性能数据分析 [Inspectors]查看数据内容 Inspectors是用于查看会话的内容,上半部分是请求的内容,下半部分是响应的内容: [Auto ...
- MongoDB安全使用指引
MongoDB社区版有三大主要安全措施,分别是安全认证.角色授权和TLS/SSL传输加密.当然除此之外,定期做数据库备份,也是很好的安全防范手段.另外,本文还将对一些提升MongoDB安全性的细节做阐 ...
- anaconda安装tensorflow报错 No module named 'tensorflow'解决方法(windows)
这个错误的原因可能是,anaconda安装的python版本为3.7,现在tensorflow仅支持python 3.6 改变python版本:首先在命令行创建一个名为python36的环境,指定 ...