NHibernate实战详解(二)映射配置与应用
关于NHibernate的资料本身就不多,中文的就更少了,好在有一些翻译文章含金量很高,另外NHibernate与Hibernate的使用方式可谓神似,所以也有不少经验可以去参考Hibernate。
本文是实战中的心得,也是NHibernate进阶教程,假设你已经看过NHibernate的文档,但对它还是觉得无法驾驭,那么你可以看看本文,或者你只是想看看其他人在实战中是如何使用它的,你也可以看看。
本文主要会涉及到这些概念,关键字:级联操作 多表查询 复杂查询 值对象
映射配置
上一篇主要介绍了领域模型设计,包括[批次]、[订单]、[任务]三个关联的模型。
这次主要解释映射中级联操作的实现。
给出hbm.xml映射配置,这也是最原始最基础的一种配置方式,注意加粗部分。
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="PP3" namespace="PP3.Domain">
<class name="PurchaseTime" table="PP3_PURCHASETIME">
<id name="ID" column="ID" type="decimal" unsaved-value="0">
<generator class="sequence">
<param name="sequence">SEQ_PURCHASETIME</param>
</generator>
</id>
<property name="Name" column="NAME" type="string" />
<set name="PurchaseOrders" inverse="true" cascade="all-delete-orphan">
<key column="TIMEID"/>
<one-to-many class="PurchaseOrder"/>
</set>
</class>
</hibernate-mapping>
前面有提到,
“一些操作订单的方法里都会有一句“order.PurchaseTime = null;”或者"order.PurchaseTime = this;",
这表示我们在批次中添加订单的同时,让订单对象也关联到批次,让订单对象可以感知到批次的存在,这一点非常重要,否则NHibernate无法执行级联操作。”
所以,在这个映射中,cascade=all-delete-orphan,inverse=true这两个属性非常关键:
<set name="PurchaseOrders" inverse="true" cascade="all-delete-orphan">
<key column="TIMEID"/>
<one-to-many class="PurchaseOrder"/>
</set>
自动生成数据库表
建立完领域模型与映射文件之后我们就不需要关注数据库了,可以使用NHibernate.Tool.hbm2ddl工具生成数据库表结构、主外键关系。
private Configuration _cfg;
_cfg = new Configuration();
_cfg.Configure()
.SetProperty("current_session_context_class", "call"); var export = new SchemaExport(_cfg);
export.Execute(true, true, false);
将current_session_context_class属性设置为call,定义session上下文的管理策略,方便单元测试,在这里并不是必须的,有兴趣可以看 这里。
业务代码
业务需求:我们要添加一批新的[订单]到一个已经存在的[批次]中,由于实际操作中是由Excel导入,我们希望每次导入时先删除原有的[订单]再添加。
//获取批次信息
PurchaseTime purchaseTime = purchaseTimeService.FindByIdContainOrders(TimeID);
purchaseTime.ClearOrders(); //删除历史数据
foreach (DataRow dr in table.Rows)
{
PurchaseOrder model = new PurchaseOrder();
……省略对象赋值代码
purchaseTime.AddOrder(model);
}
//保存批次信息
purchaseTimeService.SavePurchaseTime(purchaseTime);
代码解释:
1、首先我们获取一个已经存在的批次,也就是将[批次]持久化;
2、删除[批次]中原有的[订单],ClearOrders()方法在上一篇中已经给出具体代码,遍历批次中所有订单并打断所有订单对于该批次的依赖关系;
foreach (PurchaseOrder order in this._purchaseOrders)
{
order.PurchaseTime = null;
}
this._purchaseOrders.Clear();
3、将Excel中所有符合要求的[订单]加入到该[批次],AddOrder()方法在上一篇中已经给出具体代码;
4、保存[批次]的更新,完成;
当保存时,将会生成原有每个订单对象的delete的SQL语句,然后执行新订单的insert语句。
“purchaseTimeService.SavePurchaseTime(purchaseTime); ”业务层具体代码很简单:
public void SavePurchaseTime(PurchaseTime entity)
{
try
{
BeginTransaction();
//Session.SaveOrUpdate(entity);
new PurchaseTimeRepository().Update(entity);
Commit();
}
catch (Exception ex)
{
Rollback();
throw new Exception("保存失败:" + ex.Message);
}
}
可以使用NHibernate的Session.SaveOrUpdate保存;
因为我框架中实现了仓储,也可以像我一样new PurchaseTimeRepository().Update(entity),这些都没有关系的。
*仓储代码(打星号了,不是很关键)
public class PurchaseTimeRepository : Repository<PurchaseTime>
{ }

这样设计领域模型与映射是否有必要呢?
如果领域模型保持简单的话,那么模型中并不会有什么业务逻辑,原本的业务逻辑将会被写带业务层的Service中,
这样一来,虽然实现了仓储中的复用,但没有办法复用业务层Service中的代码了,并且会给service带来更复杂的参数,比如:
1、传入参数[批次]对象和[订单]对象集合;2、根据[批次]删除有关的所有订单;3、遍历[订单]集合并添加订单;
在NHibernate实践的道路上,我们也依然在不断探索,虽然前方总会遇到困难,但我们相信黎明一定会到来的。
下一篇将介绍一些复杂的查询和设计模式的应用。
NHibernate实战详解(二)映射配置与应用的更多相关文章
- NHibernate实战详解(一)领域模型设计
关于NHibernate的资料本身就不多,中文的就更少了,好在有一些翻译文章含金量很高,另外NHibernate与Hibernate的使用方式可谓神似,所以也有不少经验可以去参考Hibernate. ...
- Flutter完整开发实战详解
Flutter完整开发实战详解(一.Dart语言和Flutter基础) Flutter完整开发实战详解(二. 快速开发实战篇) Flutter完整开发实战详解(三. 打包与填坑篇)
- logback -- 配置详解 -- 二 -- <appender>
附: logback.xml实例 logback -- 配置详解 -- 一 -- <configuration>及子节点 logback -- 配置详解 -- 二 -- <appen ...
- C#二次开发BIMFACE系列61 File Management文件管理服务接口二次开发及实战详解
系列目录 [已更新最新开发文章,点击查看详细] 在我的博客<C#二次开发BIMFACE系列61 File Management文件管理服务接口二次开发及实战详解>最后列出了 Fil ...
- 《Android NFC 开发实战详解 》简介+源码+样章+勘误ING
<Android NFC 开发实战详解>简介+源码+样章+勘误ING SkySeraph Mar. 14th 2014 Email:skyseraph00@163.com 更多精彩请直接 ...
- oracle11实战详解
因为最近可以学习oracle了,所以昨天把oracle装好了,装的时候因为种种不知名的原因,把我的mysql居然连连不上了.说实话如果自己看教程安装的话还是有一点小复杂的,特别是对于我这种学渣来说,我 ...
- Linux中用postfix搭建邮件服务器实战详解
Linux中用postfix搭建邮件服务器实战详解 postfix是Wietse Venema在IBM的GPL协议之下开发的MTA(邮件传输代理)软件.Postfix试图更快.更容易管理.更安全,同时 ...
- Shiro 安全框架详解二(概念+权限案例实现)
Shiro 安全框架详解二 总结内容 一.登录认证 二.Shiro 授权 1. 概念 2. 授权流程图 三.基于 ini 的授权认证案例实现 1. 实现原理图 2. 实现代码 2.1 添加 maven ...
- 007-Scala类的属性和对象私有字段实战详解
007-Scala类的属性和对象私有字段实战详解 Scala类的使用实战 变量里的类必须赋初值 def函数时如果没参数可不带括号 2.不需要加Public声明 getter与setter实战 gett ...
随机推荐
- ktouch移动端事件库
最近闲来无事,写了个移动端的事件库,代码贴在下面,大家勿拍. /** @version 1.0.0 @author gangli @deprecated 移动端触摸事件库 */ (function ( ...
- 清北学堂模拟day4 捡金币
[问题描述]小空正在玩一个叫做捡金币的游戏.游戏在一个被划分成 n行 n列的网格状场地中进行.每一个格子中都放着若干金币,并且金币的数量会随着时间而不断变化. 小空的任务就是在网格中移动,拾取尽量多的 ...
- Java Sax解析
一. Java Sax解析是按照xml文件的顺序一步一步的来解析,在解析xml文件之前,我们要先了解xml文件的节点的种类,一种是ElementNode,一种是TextNode.如下面的这段boo ...
- jquery 获取datagrid行数
var data = $('#dg').datagrid('getData'); alert('总数据量:' + data.total)//注意你的数据源一定要定义了total,要不会为undefin ...
- Redis安装和使用
新年伊始,万象更新.祝大家:新的一年,工作顺利,生活越来越美好. http://www.redis.cn/commands.html http://try.redis.io/ http://www.c ...
- java 在接口里函数不能重载?
项目里使用hession远程调用serviceRemote接口,而serviceRemote接口里有两个save方法,参数分别是CpCredential对象和List,但运行发现会报莫名其妙的错. 后 ...
- Mac 命令
1.du 获取某个目录下各个文件和子目录占用多少空间,可以输入:du -sh *
- Ubuntu 14 修改默认打开方式
通过研究,有三种修改方式. 方式一: 修改路径:右上角“系统设置” -> 详细信息 -> 默认应用程序 但是,有个缺陷,可修改的项比较少. 方式二: 例如,修改pdf的打开方式,只要查看任 ...
- C#之LinQ数据库
一:与LINQ有关的语言特性 1.隐式类型 (1)源起 在隐式类型出现之前, 我们在声明一个变量的时候, 总是要为一个变量指定他的类型 甚至在foreach一个集合的时候, 也要为遍历的集合的元素,指 ...
- git之常用指令
参考:Git教程 - 廖雪峰的官方网站 1.git //linux上检测是否安装git 2.sudo apt-get install git //linux上安装git 3.git config - ...