zoukankan      html  css  js  c++  java
  • 聚合根的批量删除是不是可以批量发送请求

    DDD:聚合根的批量删除是不是可以批量发送请求

    背景

    搞了近五年的系统开发,总是抱着一种思维模式,用户的一个操作对应一个请求和一个事务,比如:用户选择了N条记录,我就会向服务器发生一个请求,服务器在一个事务中进行处理。前几天在群里一个前辈反问:批量操作难道真的要在一个事务中?这个问题让陷入了反思,谢谢前辈们(魏琼东)。

    DDD中有聚合的概念,一个聚合有且只有一个聚合根和一些其他实体,如:订单聚合中,订单是聚合根,订单明细是聚合内的实体。因为DDD中只能操作聚合根,这篇文章就介绍聚合根的批量删除问题。有人问聚合内的实体的删除咋弄?聚合内实体的删除必须伴随着聚合根的修改(这里不做详细介绍)。

    另外一点是需要注意的是,引入工作单元之后,批量操作和单个操作服务器端的逻辑是不同的,如:索引验证问题和工号生成问题(这里不做详细介绍)。

    批量删除思路

    我目前有三种选择,我记录下来,然后一个一个分析:

    1. 发送一个请求,服务器一个事务。
    2. 发送一个请求:服务器N个事务。
    3. 发送N个请求,服务器N个事务。

    发送一个请求,服务器一个事务。

    这是我之前采用的思路,现在觉得非常不好,为什么非要在一个事务中呢?如果您觉得非要在一个事务中,就告诉我一声。

    发送一个请求:服务器N个事务。

    这种思路可以接受,不过要在服务器端做额外的处理,如:收集哪些失败或成功的信息,发生给客户端,如果我不用AJAX,我就会选择这个方案。

    发送N个请求,服务器N个事务。

    考虑到我是AJAX编程,这种思路好,重分利用了客户端。

    发送N个请求,服务器N个事务的实现思路

    思路有了,实现就不是问题了,搞个队列排队发送请求就行了,当然你可以选择并行发送请求或分批次排队发送请求。

    删除的客户端逻辑

    复制代码
     1 /**
     2  * 删除功能。
     3  * 
     4  * @class Delete
     5  * @extends Happy.action.Action
     6  * @namespace Happy.table.action
     7  */
     8 Ext.define('Happy.table.action.Delete', {
     9     extend: 'Happy.action.Action',
    10     requires: [
    11         'Happy.server.PessimisticLockProxy',
    12         'Happy.Msg',
    13         'Happy.Ajax'
    14     ],
    15 
    16     DELETE_CONFIRM_TITLE: '删除确认',
    17     DELETE_CONFIRM_MSG: '确定执行删除吗?',
    18 
    19     defaultConfig: {
    20         itemId: 'delete',
    21         iconCls: 'delete-button',
    22         text: '删除',
    23         disabled: true,
    24         autoEnableAndDisable: true
    25     },
    26 
    27     /**
    28      * 契约:<br/>
    29      * <ul>
    30      *  <li>button.up('tablepanel')!==null。</li>
    31      * </ul>
    32      * @protect
    33      * @method onClickHandler
    34      * @param {Ext.button.Button} button 按钮
    35      */
    36     onClickHandler: function (button) {
    37         var me = this;
    38 
    39         var table = button.up('tablepanel');
    40         var records = table.getSelection();
    41 
    42         if (records.length == 0) {
    43             return;
    44         }
    45 
    46         Ext.Msg.confirm(me.DELETE_CONFIRM_TITLE, me.DELETE_CONFIRM_MSG, function (btn) {
    47             if (btn !== 'yes') {
    48                 return;
    49             }
    50 
    51             me.deleteRecords(records);
    52         });
    53     },
    54 
    55     /**
    56      * private
    57      * @method deleteRecords
    58      */
    59     deleteRecords: function (records) {
    60         var me = this;
    61 
    62         if (records.length == 0) {
    63             Happy.Msg.showDeleteSuccess();
    64             return;
    65         }
    66 
    67         Happy.Ajax.destroy(records.shift(), {
    68             success: function (record) {
    69                 me.deleteRecords(records);
    70             },
    71             failure: function (record, operation) {
    72                 Happy.Msg.showDeleteFailure(operation.error);
    73             }
    74         });
    75     }
    76 });
    复制代码

    删除的服务器端逻辑

    复制代码
     1         /// <summary>
     2         /// 删除。
     3         /// </summary>
     4         public ActionResult Delete(TAggregateRoot item)
     5         {
     6             this.CurrentCommandService.Execute(new TDeleteCommand
     7             {
     8                 Aggregate = item
     9             });
    10 
    11             return this.NewtonsoftJson(new
    12             {
    13                 success = true
    14             });
    15         }
    复制代码

    效果图

    备注

    这里只是演示了批量删除,有很多针对聚合根的批量操作都可以这么处理。

     

    MEF框架学习之旅(一)概念

    声明:

    本系列文章是通过网络采集并加上本人的个人理解融合而成,都好几年过去了感觉学习跟研究这个框架的人仍然很少,所以想写一个小教程帮助大家一起提高。本人技术并不是很高深,如有偏差请多多指正。参考文章如下:

    blogs.msdn.com/b/gblock/archive/tags/mef/

    www.cnblogs.com/prinsun/tag/MEF/

    http://www.cnblogs.com/wangchunming/category/341016.html

    http://www.cnblogs.com/errorif/category/295552.html

    http://www.cnblogs.com/beniao/archive/2010/08/11/1797537.html

    有些章节内容属于照搬,还请原创者原谅。也感谢其他朋友的分享。。。

    -----------------------------------------------------------------------------

    一、基本概念

    MEF:Managed Extensibility Framework,.NET 4.0中带来的一个基于托管的扩展程序开发框架, 其实MEF是为您的解决方案打破紧耦合的依赖。

    Contract:契约,即一种约定,具体在代码中表现为接口和抽象类。

    Import:导入,是部件向要通过可用导出满足的容器提出的要求, 可修饰字段、属性或构造函数参数。

    Export:导出,是部件向容器中的其他部件提供的一个值, 可修饰类、字段、属性或方法。

    1.为了使导入与导出匹配,导入和导出必须具有相同的协定。 协定由一个字符串(称为"协定名称")和已导出或导入对象的类型(称为“协定类型”)组成。只有在协定名称和协定类型均匹配时,才会认为导出能够满足特定导入。

    2.协定参数中的其中任意一个或两者可能为隐式也可能为显式。

    3.通常应对公共类或成员声明导出和导入。其他声明也受支持,但如果导出或导入私有成员、受保护成员或内部成员,将会损坏部件的隔离模型,因此建议不要这样做。

    Part:部件,即实现契约的类。

    Catalog:目录(理解意义),存放部件的地方,当需要某个部件时,会在目录中寻找。

    Container:容器,存放目录并进行部件管理,如导出、导入等。

    Compose:组装,通过容器在目录中寻找到实现了相应契约的部件,进行部件的组装。

     

    二、框架图示

     untitled

    三、基本使用示例

    启动 MEF 涉及以下几个步骤:

    添加需要容器创建的约定的导入。

    创建 MEF 用于发现部件的目录。

    创建组合部件实例的容器。

    通过对容器调用 Composeparts 方法并传入具有导入的实例,来进行组合。

     

    步骤1:创建新的控制台应用程序

     MyConsoleMEF

    2步:添加引用

    引用System.ComponentModel.Composition

      

    步骤3:创建ILogger接口

    代码段

     View Code

    4步:ILogger的实现

    代码段

    复制代码
    public class ConsoleLogger : ILogger
    
        {
    
            void ILogger.Write(string message)
    
            {
    
                Console.WriteLine(message);
    
            }
    
        }
    
        public class DebugLogger : ILogger
    
        {
    
            void ILogger.Write(string message)
    
            {
    
                Debug.WriteLine(message);
    
            }
    
        }
    
        public class EventLogLogger : ILogger
    
        {
    
            void ILogger.Write(string message)
    
            {
    
                EventLog.WriteEntry("MEFSample", message);
    
            }
    
        }
    
     
    复制代码

    步骤5:创建主程序

    代码段

    复制代码
    class Program
    
        {
    
            public ILogger[] Loggers { get; private set; }
    
            static void Main(string[] args)
    
            {
    
                Program p = new Program();
    
              
    
                foreach (var logger in p.Loggers)
    
                {
    
                    logger.Write("写日志");
    
                }
    
     
    
                Console.Read();
    
            }
    
     
    
        }
    复制代码

    6步:装饰部分

    步骤6.1:装饰部分导出

    下面的代码是使用导出属性的部分装饰

    要求为ILogger契约

    代码段

    复制代码
    [Export(typeof(ILogger))]
    
        public class ConsoleLogger : ILogger
    
        {
    
            void ILogger.Write(string message)
    
            {
    
                Console.WriteLine(message);
    
            }
    
        }
    
        [Export(typeof(ILogger))]
    
        public class DebugLogger : ILogger
    
        {
    
            void ILogger.Write(string message)
    
            {
    
                Debug.WriteLine(message);
    
            }
    
        }
    
        [Export(typeof(ILogger))]
    
        public class EventLogLogger : ILogger
    
        {
    
            void ILogger.Write(string message)
    
            {
    
                EventLog.WriteEntry("MEFSample", message);
    
            }
    
        }
    复制代码

     

    步骤6.2:装饰的需求

    下面的代码使用的是ImportMany特性,

    代码段

    [ImportMany]
    public ILogger[] Loggers { get; private set; }

     

    步骤7:组合

    下面的代码说明如何启动在MEF组成过程。

    下面的步骤用于静态构造函数: 
     创建目录 (告诉MEF寻找部件 ) 
     创建容器 (主机),并交给目录 。 
     容器调用Compose方法。 
     最后一步是从容器中获得logger

    代码段

    复制代码
    class Program
    
        {
    
            [ImportMany]
    
            public ILogger[] Loggers { get; private set; }
    
            static void Main(string[] args)
    
            {
    
                Program p = new Program();
    
     
    
                var assemblyCatalog = new AssemblyCatalog(System.Reflection.Assembly.GetExecutingAssembly());
    
                CompositionContainer container = new CompositionContainer(assemblyCatalog);
    
                var exports = container.GetExports<ILogger>();
    
     
    
                foreach (var logger in p.Loggers)
    
                {
    
                    logger.Write("写日志");
    
                }
    
    
    
                Console.Read();
    
            }
    
     
    
        }
    复制代码
     
     
     
    标签: MEF框架
  • 相关阅读:
    js将UTC时间转化为当地时区时间 用JS将指定时间转化成用户当地时区的时间
    elementUI里面,用tabs组件导致浏览器卡死的问题
    根据数组对象中的属性值删除对象
    js货币金额正则表达式
    vue elementui input不能输入的问题
    vue+elementui--$message提示框被dialog遮罩层挡住问题解决
    Oracle日期函数
    plsql查询报错:Dynamic Performamnce Tables not accessible
    Oracle rownum和rowid的区别
    Oracle通过序列实现主键自增长
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3113368.html
Copyright © 2011-2022 走看看