关于NHibernate的资料本身就不多,中文的就更少了,好在有一些翻译文章含金量很高,另外NHibernate与Hibernate的使用方式可谓神似,所以也有不少经验可以去参考Hibernate。

本文是实战中的心得,也是NHibernate进阶教程,假设你已经看过NHibernate的文档,但对它还是觉得无法驾驭,那么你可以看看本文,或者你只是想看看其他人在实战中是如何使用它的,你也可以看看。

本文主要会涉及到这些概念,关键字:级联操作 多表查询 复杂查询 值对象

接上一篇 NHibernate实战详解(一)领域模型设计

映射配置

上一篇主要介绍了领域模型设计,包括[批次]、[订单]、[任务]三个关联的模型。

这次主要解释映射中级联操作的实现。

给出hbm.xml映射配置,这也是最原始最基础的一种配置方式,注意加粗部分。

  1. <?xml version="1.0" encoding="utf-8" ?>
  2. <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="PP3" namespace="PP3.Domain">
  3. <class name="PurchaseTime" table="PP3_PURCHASETIME">
  4. <id name="ID" column="ID" type="decimal" unsaved-value="0">
  5. <generator class="sequence">
  6. <param name="sequence">SEQ_PURCHASETIME</param>
  7. </generator>
  8. </id>
  9. <property name="Name" column="NAME" type="string" />
  10. <set name="PurchaseOrders" inverse="true" cascade="all-delete-orphan">
  11. <key column="TIMEID"/>
  12. <one-to-many class="PurchaseOrder"/>
  13. </set>
  14. </class>
  15. </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工具生成数据库表结构、主外键关系。

  1. private Configuration _cfg;
  2. _cfg = new Configuration();
  3. _cfg.Configure()
  4. .SetProperty("current_session_context_class", "call");
  5.  
  6. var export = new SchemaExport(_cfg);
  7. export.Execute(true, true, false);

将current_session_context_class属性设置为call,定义session上下文的管理策略,方便单元测试,在这里并不是必须的,有兴趣可以看 这里

业务代码

业务需求:我们要添加一批新的[订单]到一个已经存在的[批次]中,由于实际操作中是由Excel导入,我们希望每次导入时先删除原有的[订单]再添加。

  1.      //获取批次信息
  2. PurchaseTime purchaseTime = purchaseTimeService.FindByIdContainOrders(TimeID);
  3. purchaseTime.ClearOrders(); //删除历史数据
  4. foreach (DataRow dr in table.Rows)
  5. {
  6. PurchaseOrder model = new PurchaseOrder();
  7.        ……省略对象赋值代码
    purchaseTime.AddOrder(model);
  8. }
  9. //保存批次信息
  10. purchaseTimeService.SavePurchaseTime(purchaseTime);

代码解释:

1、首先我们获取一个已经存在的批次,也就是将[批次]持久化;

2、删除[批次]中原有的[订单],ClearOrders()方法在上一篇中已经给出具体代码,遍历批次中所有订单并打断所有订单对于该批次的依赖关系;

  1.        foreach (PurchaseOrder order in this._purchaseOrders)
  2. {
  3. order.PurchaseTime = null;
  4. }
  5. this._purchaseOrders.Clear();

3、将Excel中所有符合要求的[订单]加入到该[批次],AddOrder()方法在上一篇中已经给出具体代码;

4、保存[批次]的更新,完成;

当保存时,将会生成原有每个订单对象的delete的SQL语句,然后执行新订单的insert语句。

“purchaseTimeService.SavePurchaseTime(purchaseTime); ”业务层具体代码很简单:

  1. public void SavePurchaseTime(PurchaseTime entity)
  2. {
  3. try
  4. {
  5. BeginTransaction();
  6. //Session.SaveOrUpdate(entity);
  7. new PurchaseTimeRepository().Update(entity);
  8. Commit();
  9. }
  10. catch (Exception ex)
  11. {
  12. Rollback();
  13. throw new Exception("保存失败:" + ex.Message);
  14. }
  15. }

可以使用NHibernate的Session.SaveOrUpdate保存;
因为我框架中实现了仓储,也可以像我一样new PurchaseTimeRepository().Update(entity),这些都没有关系的。

*仓储代码(打星号了,不是很关键)

  1. public class PurchaseTimeRepository : Repository<PurchaseTime>
  2. {
  3.  
  4. }

这样设计领域模型与映射是否有必要呢?

如果领域模型保持简单的话,那么模型中并不会有什么业务逻辑,原本的业务逻辑将会被写带业务层的Service中,

这样一来,虽然实现了仓储中的复用,但没有办法复用业务层Service中的代码了,并且会给service带来更复杂的参数,比如:

1、传入参数[批次]对象和[订单]对象集合;2、根据[批次]删除有关的所有订单;3、遍历[订单]集合并添加订单;

在NHibernate实践的道路上,我们也依然在不断探索,虽然前方总会遇到困难,但我们相信黎明一定会到来的。

下一篇将介绍一些复杂的查询和设计模式的应用。

NHibernate实战详解(二)映射配置与应用的更多相关文章

  1. NHibernate实战详解(一)领域模型设计

    关于NHibernate的资料本身就不多,中文的就更少了,好在有一些翻译文章含金量很高,另外NHibernate与Hibernate的使用方式可谓神似,所以也有不少经验可以去参考Hibernate. ...

  2. Flutter完整开发实战详解

    Flutter完整开发实战详解(一.Dart语言和Flutter基础) Flutter完整开发实战详解(二. 快速开发实战篇) Flutter完整开发实战详解(三. 打包与填坑篇)

  3. logback -- 配置详解 -- 二 -- <appender>

    附: logback.xml实例 logback -- 配置详解 -- 一 -- <configuration>及子节点 logback -- 配置详解 -- 二 -- <appen ...

  4. C#二次开发BIMFACE系列61 File Management文件管理服务接口二次开发及实战详解

    系列目录     [已更新最新开发文章,点击查看详细] 在我的博客<C#二次开发BIMFACE系列61 File Management文件管理服务接口二次开发及实战详解>最后列出了 Fil ...

  5. 《Android NFC 开发实战详解 》简介+源码+样章+勘误ING

    <Android NFC 开发实战详解>简介+源码+样章+勘误ING SkySeraph Mar. 14th  2014 Email:skyseraph00@163.com 更多精彩请直接 ...

  6. oracle11实战详解

    因为最近可以学习oracle了,所以昨天把oracle装好了,装的时候因为种种不知名的原因,把我的mysql居然连连不上了.说实话如果自己看教程安装的话还是有一点小复杂的,特别是对于我这种学渣来说,我 ...

  7. Linux中用postfix搭建邮件服务器实战详解

    Linux中用postfix搭建邮件服务器实战详解 postfix是Wietse Venema在IBM的GPL协议之下开发的MTA(邮件传输代理)软件.Postfix试图更快.更容易管理.更安全,同时 ...

  8. Shiro 安全框架详解二(概念+权限案例实现)

    Shiro 安全框架详解二 总结内容 一.登录认证 二.Shiro 授权 1. 概念 2. 授权流程图 三.基于 ini 的授权认证案例实现 1. 实现原理图 2. 实现代码 2.1 添加 maven ...

  9. 007-Scala类的属性和对象私有字段实战详解

    007-Scala类的属性和对象私有字段实战详解 Scala类的使用实战 变量里的类必须赋初值 def函数时如果没参数可不带括号 2.不需要加Public声明 getter与setter实战 gett ...

随机推荐

  1. for 循环中 i++和 ++i

    在标准C语言中, i++和 ++i的区别显而易见. 但是,当在for循环中使用 i++和 ++i的时候,会发现.只要这两种语句不用来赋值操作(作为右值,赋值给左值),那么这两种写法其实是一样的. fo ...

  2. JavaScript 学习笔记 -- String.trim + format

    最近仍在IE6徘徊,低版本的浏览器没有实现JavaScript 的trim() 和 format(). . 主要是这两个使用的比较多,先整理出来: 1.trim() -- 去除字符串中开始和结尾部分, ...

  3. Linux/CentOS配置:使用yum update更新时不升级内核的方法

    RedHat/CentOS/Fedora使用 yum update 更新时,默认会升级内核.但有些服务器硬件(特别是组装的机器)在升级内核后,新的内核可能会认不出某些硬件,要重新安装驱动,很麻烦.所以 ...

  4. MySQL性能优化的21条最佳经验【转】

    转载自http://www.cnblogs.com/jiaosq/p/5843437.html 今天,数据库的操作越来越成为整个应用的性能瓶颈了,这点对于Web应用尤其明显.关于数据库的性能,这并不只 ...

  5. linux 驱动程序中断号的申请

    1.linux下查看硬中断与软中断 硬中断:/proc/interrupts 软中断:/proc/softirqs 往往一些硬件中断号都是跟CPU所分配的硬件中断号相匹配的. 即同类型的cpu可能对同 ...

  6. nginx反向代理、优化

    本优化适合apache,nginx,squid多种等web应用,特殊的业务也可能需要略作调.生产环境linux的内核优化 net.ipv4.tcp_fin_timeout = net.ipv4.tcp ...

  7. 总结一下classpath

    今天好好研究了一下Java的classpath,什么是classpath呢?classpath就是我们输入 java xxx 的时候Java执行环境搜索xxx类文件的路径.指定这个路径有两种方式,第一 ...

  8. mongodb的sql例子(简单版)

    插入数据 db.person.insert({"name":"zfx","age":21}) 查找所有数据 db.person.find() ...

  9. 第一篇博客 iframe自适应高度

    $('iframe').load(function(){    $(this).height($(this).contents().find(document).height())})这样就适应里面内 ...

  10. [转载]javascript创建对象的几种方式

    原文链接:http://qingfeng825.iteye.com/blog/1935648 1. 工厂方法:能创建并返回特定类型对象的工厂函数(factory function). function ...