zoukankan      html  css  js  c++  java
  • NHibernate实战详解(二)映射配置与应用

    关于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>
        {
    
        }

    仓储功能设计

    总结

    上一节的领域模型里看似很复杂,可是到了业务处理就变得十分简单,一句Session.SaveOrUpdate,将好几个步骤的操作一次性持久化到数据库,并且屏蔽了细节。其实是将表模块的业务过程操作转移到了领域模型里去了。

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

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

  • 相关阅读:
    【转】HTTP 状态码详解
    程序员自我提升之粗粮与细粮
    配置Eclipse支持MacBook Pro Retina屏幕的办法(解决Retina屏幕下eclipse字体变虚的问题)
    IE6下lineheight失效:当文字与图片img在同一行中显示时lineheight失效的解决办法
    2013年第二周的总结
    为什么这么多的云存储产品却没有一个能够统一管理它们的应用出现
    微软的云笔记:OneNote+SkyDrive
    完美的外出上网解决方案随身随地享用你的专有WIFI网络(3G无线路由器+sim卡卡托+3G资费卡)
    [转]如何才能更加有效率
    Perl Note
  • 原文地址:https://www.cnblogs.com/13yan/p/3514085.html
Copyright © 2011-2022 走看看