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

本文是实战中的心得,也是NHibernate进阶教程,假设你已经看过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实践的道路上,我们也依然在不断探索,虽然前方总会遇到困难,但我们相信黎明一定会到来的。

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

最新文章

  1. BuilderParttern(建造者模式)
  2. 【原创】三分钟教你学会MVC框架——基于java web开发(2)
  3. js获取隐藏元素宽高的方法
  4. LoadRunner 多场景批处理
  5. C# Winform 窗体美化
  6. MySQL数据库表名、列名、别名区分大小写的问题
  7. 安装Adobe Dreamweaver CS6 免序列号 官方破解版
  8. Windows的同步I/O和异步I/O
  9. PL/SQL Developer使用
  10. 小白日记3:kali渗透测试之被动信息收集(二)-dig、whios、dnsenum、fierce
  11. java 中的访问修饰符
  12. Qt之模型/视图(委托)
  13. Windows系统重装
  14. axis2设置soap1.1或soap1.2协议
  15. python爬虫学习笔记(一)——环境配置(windows系统)
  16. JVM 垃圾回收GC Roots Tracing
  17. [UWP]如何实现UWP平台最佳图片裁剪控件
  18. pandas常用函数
  19. Docker 安装Hadoop HDFS命令行操作
  20. centos7虚拟机安装elasticsearch5.0.x-安装篇

热门文章

  1. 关于Mysql错误:./bin/mysqld_safe --user=mysql&amp; [1] 32710 121003 16:40:22 mysqld_safe Logging to &#39;/var/log/mysqld.log&#39;. 121003 16:40:22 mysqld_s
  2. hdu 4960 Another OCD Patient (最短路 解法
  3. php简单实用的操作文件工具类(创建、移动、复制、删除)
  4. Maven Eclipse (m2e) SCM connector for subclipse 1.10 (svn 1.8) 无法检测
  5. Myeclipse如何关联源码
  6. iOS: 聊聊 Designated Initializer(指定初始化函数)
  7. 关于SVN代码提交粒度和频率的思考
  8. JQuery可见性过滤选择器:hidden无法获取通过visibility:hidden样式隐藏的元素-遁地龙卷风
  9. 【转】phpcms-v9中关于模型的理解
  10. apache 访问出现403 Forbidden