项目架构开发:数据访问层之UnitOfWork
本章我们继续IUnitOfWork的开发,从之前的IRepository接口中就可以看出,我们并没有处理单元事务,
数据CUD每次都是立即执行的,这样有一些不好的地方,比如数据访问次数会增多,一笔数据的完整性无法保证
比如:批量新增2条记录,只有一条成功,这样的情况就应该Rollback;可能有人已经想到用数据库自带的事务保证完整性
虽然是可以,但是这样就不可避免地在业务层耦合SqlTransaction,我不想这种情况出现;
所以我们用windows自带的分布式事务TransactionScope来实现,TransactionScope可以实现多个数据库的事务锁,这点就比SqlTransaction强一些
当然我了解到分布式事务是不一般的复杂的,那些更好的处理方式我还没有掌握,所以先这么写吧,有这方面经验的朋友欢迎提建议
IUnitOfWork.cs
public interface IUnitOfWork<T> where T : class
{
void RegisterAdd(T entity, Action callback);
void RegisterUpdate(T entity, Action callback);
void RegisterDelete(T entity, Action callback);
void Commit();
}
注册新增操作:RegisterAdd
注册更新操作:RegisterUpdate
注册修改操作:RegisterDelete
提交数据:Commit
工作单元的实现
public class UnitOfWork<T> : IUnitOfWork<T> where T : class
{
private Dictionary<T, Action> addEntities;
private Dictionary<T, Action> updateEntities;
private Dictionary<T, Action> deleteEntities; public UnitOfWork()
{
addEntities = new Dictionary<T, Action>();
updateEntities = new Dictionary<T, Action>();
deleteEntities = new Dictionary<T, Action>();
} public void RegisterAdd(T entity, Action callback)
{
this.addEntities.Add(entity, callback);
} public void RegisterUpdate(T entity, Action callback)
{
this.updateEntities.Add(entity, callback);
} public void RegisterDelete(T entity, Action callback)
{
this.deleteEntities.Add(entity, callback);
} public void Commit()
{
using (TransactionScope scope = new TransactionScope())
{
foreach (var entity in deleteEntities.Keys)
{
this.deleteEntities[entity]();
} foreach (var entity in updateEntities.Keys)
{
this.updateEntities[entity]();
} foreach (var entity in addEntities.Keys)
{
this.addEntities[entity]();
} scope.Complete();
}
}
}
这里我们用了Action,这个是无返回值委托方法,如果大家需要返回值可以用Func
实现我们还是用DapperRepository,修改一下。在新增方法中注册数据持久化方法
好了,现在我们来看看测试结果
测试工作单元
还是用原来那个DapperRepositoryTest
我们修改一下实现过程:
单个新增
批量新增
运行结果
我们把表结构改一下,名称改成不能为null
AddBatch也要修改,正常的执行结果一个是抛出异常
[TestMethod]
public void AddBatch()
{
try
{
var loginUser1 = new LoginUser()
{
Id = Guid.NewGuid(),
LoginName = "lanxiaoke-" + Guid.NewGuid().ToString(),
Password = "mima1987",
IsEnabled = ,
CreateTime = DateTime.Now
}; var loginUser2 = new LoginUser()
{
Id = Guid.NewGuid(),
//LoginName = "lanxiaoke-" + Guid.NewGuid().ToString(),
Password = "mima1987",
IsEnabled = ,
CreateTime = DateTime.Now
}; var list = new List<LoginUser>();
list.Add(loginUser1);
list.Add(loginUser2); repository.AddBatch(list);
unitOfWork.Commit();
}
catch (Exception ex)
{
var err = ex.Message;
} //long count = repository.Count(t => t.LoginName.In(new string[] { loginUser1.LoginName, loginUser2.LoginName })); //Assert.AreEqual(true, count >0);
}
运行看看
如期运行,到这里,工作单元就讲完了
完整项目架构
我们来看看完整的数据访问层架构
整个数据访问层就讲完了,虽然有些简陋,但是基本功能都有了
项目架构开发系列
- 项目架构开发:数据访问层之Cache
- 项目架构开发:数据访问层之Logger
- 项目架构开发:数据访问层之Query
- 项目架构开发:数据访问层之Repository
- 项目架构开发:数据访问层之UnitOfWork
项目架构开发:数据访问层之UnitOfWork的更多相关文章
- 项目架构开发:数据访问层之UnitOfWork (补充)
应lisansi同学回复(项目架构开发:数据访问层之UnitOfWork)要求,补上Dapper的DbContext实现 using Dapper.Contrib.Extensions; using ...
- 企业级应用架构(三)三层架构之数据访问层的改进以及测试DOM的发布
在上一篇我们在宏观概要上对DAL层进行了封装与抽象.我们的目的主要有两个:第一,解除BLL层对DAL层的依赖,这一点我们通过定义接口做到了:第二,使我们的DAL层能够支持一切数据访问技术,如Ado.n ...
- 项目架构开发:数据访问层之Cache
数据访问层简单介绍 数据访问层,提供整个项目的数据访问与持久化功能.在分层系统中所有有关数据访问.检索.持久化的任务,最终都将在这一层完成. 来看一个比较经典的数据访问层结构图 大概可以看出如下信息 ...
- 项目架构开发:数据访问层之Logger
接上文 项目架构开发:数据访问层之Cache 本章我们继续ILogger的开发 ILogger.cs public interface ILogger { void Info(object messa ...
- 项目架构开发:数据访问层之Repository
接上文 项目架构开发:数据访问层之Logger 本章我们继续IRepository开发,这个仓储与领域模式里边的仓储有区别,更像一个工具类,也就是有些园友说的“伪仓储”, 这个仓储只实现单表的CURD ...
- 项目架构开发:数据访问层之Query
接上文 项目架构开发:数据访问层之Repository 上一章我们讲了IRepository接口,这张我们来讲IQuery 根据字面意思就可以知道,这次主要讲数据查询,上一章我们只针对单表做了查询的操 ...
- 随机获得MySQL数据库中100条数据方法 驾照题库项目 MVC架构 biz业务层的实现类 根据考试类型rand或order通过dao数据访问层接口得到数据库中100或全部数据
package com.swift.jztk.biz; import java.util.Collections; import java.util.Comparator; import java.u ...
- 数据访问层之Repository
数据访问层之Repository 接上文 项目架构开发:数据访问层之Logger 本章我们继续IRepository开发,这个仓储与领域模式里边的仓储有区别,更像一个工具类,也就是有些园友说的“伪 ...
- asp.net/wingtip/创建数据访问层
一. 什么是数据访问层 在wingtip项目中,数据访问层是对以下三者的总称:1. product类等数据相关的实体类(class)2. 数据库(database),对实体类成员的存储3. 上述二者的 ...
随机推荐
- checkbox、radio控件和文字不对其
一般使用html控件的时候 单选按钮和复选框的控件和文字不对齐 给input控件加上 style="vertical-align: middle; margin-top: -2px; ...
- 配置Log4J(转载)
Log4J的配置文件(Configuration File)就是用来设置记录器的级别.存放器和布局的,它可接key=value格式的设置或xml格式的设置信息.通过配置,可以创建出Log4J的运行环境 ...
- Angular - - $interpolate 和 $parse
$interpolate 将一个字符串编译成一个插值函数.HTML编译服务使用这个服务完成数据绑定. 使用:$interpolate(text,[mustHaveExpression],[truste ...
- 【HDU 5808】 Price List Strike Back (整体二分+动态规划)
Price List Strike Back There are nn shops numbered with successive integers from 11 to nn in Bytelan ...
- 第五组UI组件:ProgressBar及其子类
ProgressBar组件也是一组重要的组件,ProgressBar本身代表了进度条组件,它还派生了两个常用的组件:SeekBar和RatingBar.ProgressBar及其子类在用上十分相似,只 ...
- EXP/IMP 命令参数
http://www.cnblogs.com/sopost/archive/2010/01/19/2190125.html 1.EXP: 1.完全: EXP ...
- Canvas 颜色反转
ImageData中的元素反转颜色 255-data[i,i+1,i+2] <!DOCTYPE html> <html lang="en"> <hea ...
- js数组快速排序
<script type="text/javascript"> var arr = [1, 2, 3, 54, 22, 1, 2, 3]; function quick ...
- 以Tomcat+Mysql为例,实现Docker多容器连接
Docker提供了多个容器直接访问的方法,最简单的方式是直接使用端口映射-p参数指定映射的端口或者-P映射所有端口,多个容器直接通过网络端口进行访问. 但网络端口映射方式并不是Docker中连接多个容 ...
- [nRF51822] 16、nRF51822的随机数生成器,及随机数生成器的一些知识(可以帮您补补随机数发生器的知识)
1.前言 随机数生成器在通信.加密.图像传输等领域应用广泛,且一般起到关键性作用.我在最近设计的一个近场射频通信协议的碰撞避退算法的过程中,便对此有深深体会. 2.伪随机数发生器 随机数发生器一般包括 ...