(转).Net高级进阶,在复杂的业务逻辑下,如何以最简练的代码,最直观的编写事务代码?
原文地址:http://www.cnblogs.com/1996V/p/7798111.html
示例一和示例二,主要是来讲解 TransactionScope 是什么,为什么要用TransactionScope。
示例三(重要)则是优化写法,增加代码的灵活性和可读性。
【示例一】
现在,你要写个入库接口,大致意思就是: 勾选一条商品,然后写上数量,点击入库按钮,将会产生一条入库记录,同时 这个商品的所对应的 库存数量 也会 更新。
因为涉及到库存,所以要用事务来保证数据安全。
StorageTask:入库作业表,存写入库记录
GoodsInventory:商品库存表, 里面放的是 不同商品的 详细介绍、数量等信息
那么我们的实现 , 可能是 这样的 , 如图:
上图的代码,我们主要是先看 商品入库操作 GoodsInventoryOperate 这个Dal方法,放图:
上面的这是一个Dal方法,事务写法很大众,很常规,代码没毛病。
【示例二】
好,现在,我们的业务要求要改一下,改成这样的:
勾选了一条商品,输入该条商品的入库数量,然后又勾选了一条原材料,输入该原材料的入库数量,最终点击入库按钮,要 产生 商品的入库记录和原材料的入库记录, 还要 分别修改 所对应的 商品库存表和原材料库存表 的 库存数量
那么,我们就要修改下这个接口,首先,参数由原来的 单行的参数 改为 集合形式的 参数,
那么我们的接口代码也随之修改,如下图:
然后我们在看看 这个入库操作方法 InventoryOperate
我们来对比下,我们把之前的 商品入库操作 GoodsInventoryOperate 方法 给改成了 入库操作方法 InventoryOperate 。
实际上,入库操作方法 InventoryOperate = 商品入库操作 + 原材料入库操作 ,但是因为 业务的更改,让我们不得不把
原本 Dal层中的两个方法代码 给 复制粘贴到一起,形成第三个方法,也就是入库操作方法 InventoryOperate 。
那么,有没有一种写法,能让我们 更简单更方便 不用每次复制粘贴代码形式 来实现 事务的编写?
有!
TransactionScope:
在早期.net时代,如果想使用事务,就用SqlTransaction来实现,而每个SqlTransaction都会用同一个SqlConnection连接对象。
如果逻辑简单还好说,如果逻辑稍微复杂的话,想用多个Dal方法来共同组合一个事务的话,就非常费脑筋的,就像上文这样演变的 第一版 和 第二版。
为此,在.Net2.0时代,TransactionScope诞生了,微软官方描述:代码块事务,还有一个别称:分布式事务。
它实现了IDisposable接口,可以把它被实例化开始到被Dispose掉之间的代码作为一个事务,也就是它的存在,最终让你的代码块所嵌套在其中多个DAL方法变成“一个方法”
那么,当我们使用它以后,我们就可以这样编写:
【示例三】
现在,大家对 TransactionScope 有了基本的印象,那么现在考虑到代码的可读性和灵活性,我将要对当前风格再次改写,通过委托的形式让代码结构层次更加分明。
1 /// <summary>
2 /// 事务语句统一执行
3 /// </summary>
4 /// <param name="ac">委托</param>
5 /// <returns></returns>
6 public static bool TransactionExecute(Action ac)
7 {
8 try
9 {
10 using (TransactionScope ts = new TransactionScope())
11 {
12 ac.Invoke();
13 ts.Complete();
14 }
15 return true;
16 }
17 catch
18 {
19 return false;
20 }
21 }
然后,我们的接口方法的编码变成了这样:
1 /// <summary>
2 /// 商品仓库的入库作业操作
3 /// </summary>
4 /// <param name="iData">入库数据集合</param>
5 /// <returns></returns>
6 public string WarehouseGoodsOperate(List<InboundModel> iData)
7 {
8 Action ac = () => { };//声明一个委托
9 foreach (InboundModel item in iData)
10 {
11 if (item.type == "商品")
12 {
13 ac += () =>
14 {
15 IServices.Insert(item);
16 IServices.UpdateGoods(item);
17 };
18 }
19 if (item.type == "原材料")
20 {
21 ac += () =>
22 {
23 IServices.Insert(item);
24 IServices.UpdateInventory(item);
25 };
26 }
27 }
28 if (IServices.TransactionExecute(ac))
29 {
30 return "成功";
31 }
32 return "失败";
33 }
通过上面这样的写法,最终让代码风格更干净,同时在 事务的 处理上更灵活方便, 我们只需要把想要执行的 方法 让 ac 给包进去, 最后在调用 TransactionExecute 统一执行。
基于自己的场景可以定制自己的TransactionExecute,本文着重指出利用委托来优化该情况下的编码思想,至于TransactionExecute,这里只是做个简单的科普,其中有更多可挖掘的地方,感兴趣的童鞋可以自行百度。
当然,采用这种委托写法,需要注意一点:
因为 类 是 引用类型 ,传递的地址和值类型不同, 所以最终你的委托执行的是 你最后对实例的更改, 所以你认为的能行,实际上是不能行。
那么,怎样解决这样情况?
逐个逐个的赋值,或者用反射?
不用,我们可以通过继承 ICloneable 接口,然后通过浅复制的方式实现Clone方法。
class SysUser : ICloneable
{
public object Clone()
{
return this.MemberwiseClone();
}
}
最后,我们就可以这样:
让正确的程序更快比让快速的程序正确要容易的多
(转).Net高级进阶,在复杂的业务逻辑下,如何以最简练的代码,最直观的编写事务代码?的更多相关文章
- .Net高级进阶,在复杂的业务逻辑下,如何以最简练的代码,最直观的编写事务代码?
本文将通过场景例子演示,来通俗易懂的讲解在复杂的业务逻辑下,如何以最简练的代码,最直观的编写事务代码. 通过一系列优化最终达到两个效果,1.通过代码块来控制事务(分布式事务),2.通过委托优化Tran ...
- 潭州学院-JavaVIP的Javascript的高级进阶-KeKe老师
潭州学院-JavaVIP的Javascript的高级进阶-KeKe老师 讲的不错,可以学习 下面是教程的目录截图: 下载地址:http://www.fu83.cn/thread-283-1-1.htm ...
- C#可扩展编程之MEF学习笔记(五):MEF高级进阶
好久没有写博客了,今天抽空继续写MEF系列的文章.有园友提出这种系列的文章要做个目录,看起来方便,所以就抽空做了一个,放到每篇文章的最后. 前面四篇讲了MEF的基础知识,学完了前四篇,MEF中比较常用 ...
- 高级进阶DB2(第2版)——内部结构、高级管理与问题诊断
<高级进阶DB2(第2版)——内部结构.高级管理与问题诊断> 基本信息 作者: 牛新庄 出版社:清华大学出版社 ISBN:9787302323839 上架时间:2013-7-3 出版 ...
- MEF高级进阶
MEF高级进阶 好久没有写博客了,今天抽空继续写MEF系列的文章.有园友提出这种系列的文章要做个目录,看起来方便,所以就抽空做了一个,放到每篇文章的最后. 前面四篇讲了MEF的基础知识,学完了前四 ...
- .Net高级进阶,WebApi和MVC进行模型验证的时候,教你如何自由控制需要进行验证的字段?
现在,你有一个MVC架构的web项目,你要完成一个注册功能. 前台传了3个值到你的控制器,分别是账号.密码.邮箱. 如图:现在你要在控制器里面判断,账号名称.密码.邮箱不能为空,并且名称和密码不超过1 ...
- DDD实战进阶第一波(八):开发一般业务的大健康行业直销系统(业务逻辑条件判断最佳实践)
这篇文章其实是大健康行业直销系统的番外篇,主要给大家讲讲如何在领域逻辑中,有效的处理业务逻辑条件判断的最佳实践问题. 大家都知道,聚合根.实体和值对象这些领域对象都自身处理自己的业务逻辑.在业务处理过 ...
- .Net高级进阶,教你如何构建企业模型数据拦截层,动态控制字段验证
现在,你有一个MVC架构的web项目,你要完成一个注册功能. 前台传了3个值到你的控制器,分别是账号.密码.邮箱. 如图:现在你要在控制器里面判断,账号名称.密码.邮箱不能为空,并且名称和密码不超过1 ...
- 《Android高级进阶》读书笔记
<Android高级进阶>是据我所知的市面上唯一一本技术工具书,比较的高大全,作者的目的是为了对全领域有个初步的概念 No1: 在Android系统中,拥有事件传递处理能力的类有以下三种 ...
随机推荐
- MySql安装完成后,Navicat连接不上的问题
Navicat连接mysql8.0.1版本出现1251--Client does not support authentication protocol requested by server的解决 ...
- 转-[WebServer] Windows操作系统下 Tomcat 服务器运行 PHP 的环境配置
原文 前言: 由于本人在开发和学习过程中需要同时部署 JavaWeb 和 PHP 项目,于是整理了网上的一些相关资料,并结合自己的实际操作,记录于此,以供参考. 一.环境(64bit): 1.操作系统 ...
- MySQL 的数据类型,有哪些?
table th:first-of-type { width: 100px; } MySQL数据类型选择指南:https://www.awaimai.com/1146.html 实数: 数据类型 多少 ...
- django使用session报错:no such table: django_session
Django版本:1.11.15 使用session的代码:request.session['key'] = value 运行后报错:no such table: django_session 解决办 ...
- R3注入的四种方式
DLL注入 1.首先要获取想要注入的进程句柄(OpenProcess) 2.从要注入的进程的地址空间中分配一段内存(VirtualAllocEx) 3.往分配的内存位置写入要注入的DLL名称(Writ ...
- PostgreSQL的下载安装
下载地址:http://www.postgres.cn/download 下载地址:http://www.filehorse.com/download-postgresql-64/ 下载地址2:htt ...
- GTP+SDI工程播出部分思路整理(2)
GTP+SDI工程播出部分思路整理(2) 以同样的方法来分析tx_video_a_c_in信号: SDI核中tx_video_a_c_in信号连接情况如下所示 .tx_video_a_c_in ...
- MobaXterm的一些介绍(Top 5 SSH Clients for Windows (Alternatives of PuTTY))
Top 5 SSH Clients for Windows (Alternatives of PuTTY) http://tecadmin.net/top-5-ssh-clients-for-wind ...
- 解决iScroll横向滚动区域无法拉动页面的问题
近期项目中使用iScroll遇到一个问题,在设定wrapper为横向滚动时,如果你手指放在该区域,将无法拉动页面,也就是说该区域取消了默认事件.这个体验是实在是无法接受,特别是页面中有多个横向滚动区域 ...
- WPF动态时间(电子表)
private DispatcherTimer dispatcherTimer; public MainWindow() { InitializeComponent(); dispatcherTime ...