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

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框架
原文地址:https://www.cnblogs.com/Leo_wl/p/3113368.html