聚合根的批量删除是不是可以批量发送请求
DDD:聚合根的批量删除是不是可以批量发送请求
背景
搞了近五年的系统开发,总是抱着一种思维模式,用户的一个操作对应一个请求和一个事务,比如:用户选择了N条记录,我就会向服务器发生一个请求,服务器在一个事务中进行处理。前几天在群里一个前辈反问:批量操作难道真的要在一个事务中?这个问题让陷入了反思,谢谢前辈们( 魏琼东 )。
DDD中有聚合的概念,一个聚合有且只有一个聚合根和一些其他实体,如:订单聚合中,订单是聚合根,订单明细是聚合内的实体。因为DDD中只能操作聚合根,这篇文章就介绍聚合根的批量删除问题。有人问聚合内的实体的删除咋弄?聚合内实体的删除必须伴随着聚合根的修改(这里不做详细介绍)。
另外一点是需要注意的是,引入工作单元之后,批量操作和单个操作服务器端的逻辑是不同的,如:索引验证问题和工号生成问题(这里不做详细介绍)。
批量删除思路
我目前有三种选择,我记录下来,然后一个一个分析:
发送一个请求,服务器一个事务。 发送一个请求:服务器N个事务。 发送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 }
效果图
备注
这里只是演示了批量删除,有很多针对聚合根的批量操作都可以这么处理。
随笔- 9 文章- 0 评论- 21
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 :组装,通过容器在目录中寻找到实现了相应契约的部件,进行部件的组装。
二、框架图示
三、基本使用示例
启动 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框架
作者: Leo_wl
出处: http://www.cnblogs.com/Leo_wl/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
版权信息查看更多关于聚合根的批量删除是不是可以批量发送请求的详细内容...