在进行数据库添加、修改、删除时,为了保证事务的一致性,即操作要么全部成功,要么全部失败。例如银行A、B两个账户的转账业务。一方失败都会导致事务的不完整性,从而事务回滚。而工作单元模式可以跟踪事务,在操作完成时对事务进行统一提交。

具体实践

首先,讲解下设计思想:领域层通过相应的库实现泛型仓储接口来持久化聚合类,之后在抽象库中将对泛型仓储接口提供基础实现,并将对应的实体转化为SQl语句。这样领域层就不需要操作Sql语句即可完成CRUD操作,同时使用工作单元对事务进行统一提交。

1)定义仓储接口,包含基本的CRUD操作及其重载不同的查询

public interface IRepository<T>
{
/// <summary>
/// 插入对象
/// </summary>
/// <param name="entity"></param>
int Insert(T entity); /// <summary>
/// 更新对象
/// </summary>
/// <param name="entity"></param>
/// <param name="predicate"></param>
int Update(T entity, Expression<Func<T, bool>> express); /// <summary>
/// 删除对象
/// </summary>
/// <param name="predicate"></param>
int Delete(Expression<Func<T, bool>> express = null); /// <summary>
/// 查询对象集合
/// </summary>
/// <param name="predicate"></param>
/// <returns></returns>
List<T> QueryAll(Expression<Func<T, bool>> express = null); /// <summary>
/// 查询对象集合
/// </summary>
/// <param name="index"></param>
/// <param name="pagesize"></param>
/// <param name="order"></param>
/// <param name="asc"></param>
/// <param name="express"></param>
/// <returns></returns>
List<T> QueryAll(int index,int pagesize,List<PropertySortCondition> orderFields, Expression<Func<T, bool>> express = null); /// <summary>
/// 查询对象集合
/// </summary>
/// <param name="type"></param>
/// <param name="predicate"></param>
/// <returns></returns>
List<object> QueryAll(Type type, Expression<Func<T, bool>> express = null); /// <summary>
/// 查询对象
/// </summary>
/// <param name="predicate"></param>
/// <returns></returns>
T Query(Expression<Func<T, bool>> express); /// <summary>
/// 查询数量
/// </summary>
/// <param name="predicate"></param>
/// <returns></returns>
object QueryCount(Expression<Func<T, bool>> express = null);
}

其次,对仓储接口提供基本实现,这里由于使用了Lambda表达式,所以就需要进行表达式树的解析(这里我希望园友能自己去研究)。

public abstract class BaseRepository<T> : IRepository<T>
where T:class,new()
{
private IUnitOfWork unitOfWork; private IUnitOfWorkContext context; public BaseRepository(IUnitOfWork unitOfWork, IUnitOfWorkContext context)
{
this.unitOfWork = unitOfWork;
this.context = context;
} Lazy<ConditionBuilder> builder = new Lazy<ConditionBuilder>(); public string tableName {
get
{
TableNameAttribute attr= (TableNameAttribute)typeof(T).GetCustomAttribute(typeof(TableNameAttribute));
return attr.Name;
}
} /// <summary>
/// 插入对象
/// </summary>
/// <param name="entity"></param>
public virtual int Insert(T entity)
{
Func<PropertyInfo[], string, IDictionary<string, object>, int> excute = (propertys, condition, parameters) =>
{
List<string> names = new List<string>();
foreach (PropertyInfo property in propertys)
{
if (property.GetCustomAttribute(typeof(IncrementAttribute)) == null)
{
string attrName = property.Name;
object value = property.GetValue(entity);
names.Add(string.Format("@{0}", attrName));
parameters.Add(attrName, value);
}
}
string sql = "Insert into {0} values({1})";
string combineSql = string.Format(sql, tableName, string.Join(",", names), builder.Value.Condition);
return unitOfWork.Command(combineSql, parameters);
};
return CreateExcute<int>(null, excute);
} /// <summary>
/// 修改对象
/// </summary>
/// <param name="entity"></param>
/// <param name="express"></param>
public virtual int Update(T entity, Expression<Func<T, bool>> express)
{ Func<PropertyInfo[], string, IDictionary<string, object>, int> excute = (propertys, condition, parameters) =>
{
List<string> names = new List<string>();
foreach (PropertyInfo property in propertys)
{
if (property.GetCustomAttribute(typeof(IncrementAttribute)) == null)
{
string attrName = property.Name;
object value = property.GetValue(entity);
names.Add(string.Format("{0}=@{1}", attrName, attrName));
parameters.Add(attrName, value);
}
}
string sql = "update {0} set {1} where {2}";
string combineSql = string.Format(sql, tableName, string.Join(",", names), builder.Value.Condition);
return unitOfWork.Command(combineSql, parameters);
};
return CreateExcute<int>(express, excute);
}
/// <summary>
/// 删除对象
/// </summary>
/// <param name="express"></param>
public virtual int Delete(Expression<Func<T, bool>> express = null)
{
Func<PropertyInfo[], string, IDictionary<string, object>, int> excute = (propertys, condition, parameters) =>
{
string sql = "delete from {0} {1}";
string combineSql = string.Format(sql, tableName, condition);
return unitOfWork.Command(combineSql, parameters);
};
return CreateExcute<int>(express, excute);
} /// <summary>
/// 查询对象集合
/// </summary>
/// <param name="express"></param>
/// <returns></returns>
public virtual List<T> QueryAll(Expression<Func<T, bool>> express = null)
{
Func<PropertyInfo[], string, IDictionary<string, object>, List<T>> excute = (propertys, condition, parameters) =>
{
string sql = "select {0} from {1} {2}";
string combineSql = string.Format(sql, string.Join(",", propertys.Select(x => x.Name)), tableName, condition);
return context.ReadValues<T>(combineSql, parameters);
};
return CreateExcute<List<T>>(express, excute);
} /// <summary>
/// 查询对象集合(分页)
/// </summary>
/// <param name="index"></param>
/// <param name="pagesize"></param>
/// <param name="order"></param>
/// <param name="asc"></param>
/// <param name="express"></param>
/// <returns></returns>
public virtual List<T> QueryAll(int index,int pagesize,List<PropertySortCondition> orderFields,Expression<Func<T, bool>> express = null)
{
Func<PropertyInfo[], string, IDictionary<string, object>, List<T>> excute = (propertys, condition, parameters) =>
{
if (orderFields == null) { throw new Exception("排序字段不能为空"); }
string sql = "select * from (select {0} , ROW_NUMBER() over(order by {1}) as rownum from {2} {3}) as t where t.rownum >= {4} and t.rownum < {5}";
string combineSql = string.Format(sql, string.Join(",", propertys.Select(x => x.Name)),string.Join(",", orderFields), tableName, condition, (index - ) * pagesize + , index * pagesize);
return context.ReadValues<T>(combineSql, parameters);
};
return CreateExcute<List<T>>(express, excute);
} /// <summary>
/// 查询对象集合
/// </summary>
/// <param name="type"></param>
/// <param name="express"></param>
/// <returns></returns>
public virtual List<object> QueryAll(Type type, Expression<Func<T, bool>> express = null)
{
Func<PropertyInfo[], string, IDictionary<string, object>, List<object>> excute = (propertys, condition, parameters) =>
{
string sql = "select {0} from {1} {2}";
string combineSql = string.Format(sql, string.Join(",", propertys.Select(x => x.Name)), tableName, condition);
return context.ReadValues(combineSql, type, parameters);
};
return CreateExcute<List<object>>(express, excute);
} /// <summary>
/// 查询对象
/// </summary>
/// <param name="express"></param>
/// <returns></returns>
public virtual T Query(Expression<Func<T, bool>> express)
{
Func<PropertyInfo[], string, IDictionary<string, object>, T> excute = (propertys, condition, parameters) =>
{
string sql = "select {0} from {1} {2}";
string combineSql = string.Format(sql, string.Join(",", propertys.Select(x => x.Name)), tableName, condition);
return context.ExecuteReader<T>(combineSql, parameters);
};
return CreateExcute<T>(express, excute);
} /// <summary>
/// 查询数量
/// </summary>
/// <param name="express"></param>
/// <returns></returns>
public virtual object QueryCount(Expression<Func<T, bool>> express = null)
{
Func<PropertyInfo[], string, IDictionary<string, object>, object> excute = (propertys, condition, parameters) =>
{
string sql = "select * from {0} {1}";
string combineSql = string.Format(sql, string.Join(",", propertys.Select(x => x.Name)), tableName, condition);
return context.ExecuteScalar(combineSql, parameters);
}; return CreateExcute<object>(express, excute);
} private TValue CreateExcute<TValue>(Expression<Func<T, bool>> express, Func<PropertyInfo[], string, IDictionary<string, object>, TValue> excute)
{
Dictionary<string, object> parameters = new Dictionary<string, object>();
PropertyInfo[] propertys = typeof(T).GetProperties();
string condition = "";
if (express != null)
{
builder.Value.Build(express, tableName);
condition = string.Format("where {0} ", builder.Value.Condition);
for (int i = ; i < builder.Value.Arguments.Length; i++)
{
parameters.Add(string.Format("Param{0}", i), builder.Value.Arguments[i]);
}
}
return excute(propertys, condition, parameters);
}
}

接下来,定义工作单元,所有的添加、删除、修改操作都会被储存到工作单元中。

public interface IUnitOfWork
{
/// <summary>
/// 命令
/// </summary>
/// <param name="commandText"></param>
/// <param name="parameters"></param>
/// <returns></returns>
int Command(string commandText, IDictionary<string, object> parameters); /// <summary>
/// 事务的提交状态
/// </summary>
bool IsCommited { get; set; } /// <summary>
/// 提交事务
/// </summary>
/// <returns></returns>
void Commit(); /// <summary>
/// 回滚事务
/// </summary>
void RollBack();
}

接下来是对工作单元的实现,其内部维护了一个命令集合,存储Sql语句。

public class UnitOfWork:IUnitOfWork
{
/// <summary>
/// 注入对象
/// </summary>
private IUnitOfWorkContext context; /// <summary>
/// 维护一个Sql语句的命令列表
/// </summary>
private List<CommandObject> commands; public UnitOfWork(IUnitOfWorkContext context)
{
commands = new List<CommandObject>();
this.context = context;
} /// <summary>
/// 增、删、改命令
/// </summary>
/// <param name="commandText"></param>
/// <param name="parameters"></param>
/// <returns></returns>
public int Command(string commandText, IDictionary<string, object> parameters)
{
IsCommited = false;
commands.Add(new CommandObject(commandText, parameters));
return ;
} /// <summary>
/// 提交状态
/// </summary>
public bool IsCommited{ get; set; } /// <summary>
/// 提交方法
/// </summary>
/// <returns></returns>
public void Commit()
{
if (IsCommited) { return ; }
using (TransactionScope scope = new TransactionScope())
{
foreach (var command in commands)
{
context.ExecuteNonQuery(command.command, command.parameters);
}
scope.Complete();
IsCommited = true;
}
} /// <summary>
/// 事务回滚
/// </summary>
public void RollBack()
{
IsCommited = false;
}
}

最后定义工作单元对事务提交处理的上下文及其实现,同仓储模式中的代码。

public interface IUnitOfWorkContext
{ /// <summary>
/// 注册新对象到上下文
/// </summary>
/// <param name="commandText"></param>
/// <param name="parameters"></param>
int ExecuteNonQuery(string commandText, IDictionary<string, object> parameters = null); /// <summary>
/// 查询对象集合
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="commandText"></param>
/// <param name="parameters"></param>
/// <param name="load">自定义处理</param>
/// <returns></returns>
List<T> ReadValues<T>(string commandText, IDictionary<string, object> parameters = null, Func<IDataReader, T> load = null) where T : class, new(); /// <summary>
/// 查询对象集合
/// </summary>
/// <param name="commandText"></param>
/// <param name="type"></param>
/// <param name="parameters"></param>
/// <param name="setItem"></param>
/// <returns></returns>
List<object> ReadValues(string commandText, Type type, IDictionary<string, object> parameters = null, Action<dynamic> setItem = null); /// <summary>
/// 查询对象
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="commandText"></param>
/// <param name="parameters"></param>
/// <param name="excute"></param>
/// <returns></returns>
T ExecuteReader<T>(string commandText, IDictionary<string, object> parameters = null, Func<IDataReader, T> load = null) where T : class,new(); /// <summary>
/// 查询数量
/// </summary>
/// <param name="commandText"></param>
/// <param name="parameters"></param>
/// <returns></returns>
object ExecuteScalar(string commandText, IDictionary<string, object> parameters = null);
}

最后实现。

public abstract class UnitOfWorkContext : IUnitOfWorkContext,IDisposable
{
/// <summary>
/// 数据库连接字符串标识
/// </summary>
public abstract string Key { get; } private SqlConnection connection; private SqlConnection Connection
{
get
{
if (connection == null)
{
ConnectionStringSettings settings = ConfigurationManager.ConnectionStrings[Key];
connection = new SqlConnection(settings.ConnectionString);
}
return connection;
}
} /// <summary>
/// 注册新对象到事务
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="entity"></param>
public int ExecuteNonQuery(string commandText, IDictionary<string, object> parameters = null)
{
Func<SqlCommand, int> excute = (commend) =>
{
return commend.ExecuteNonQuery();
};
return CreateDbCommondAndExcute<int>(commandText, parameters, excute);
} /// <summary>
/// 查询对象集合
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="commandText"></param>
/// <param name="parameters"></param>
/// <param name="load">自定义处理</param>
/// <returns>泛型实体集合</returns> public List<T> ReadValues<T>(string commandText, IDictionary<string, object> parameters = null, Func<IDataReader, T> load = null) where T : class,new()
{
Func<SqlCommand, List<T>> excute = (dbCommand) =>
{
List<T> result = new List<T>();
using (IDataReader reader = dbCommand.ExecuteReader())
{
while (reader.Read())
{
if (load == null)
{
load = (s) => { return s.GetReaderData<T>(); };
}
var item = load(reader);
result.Add(item);
}
return result;
}
};
return CreateDbCommondAndExcute(commandText, parameters, excute);
} /// <summary>
/// 查询对象集合
/// </summary>
/// <param name="commandText"></param>
/// <param name="parameters"></param>
/// <param name="setItem"></param>
/// <returns></returns>
public List<object> ReadValues(string commandText, Type type, IDictionary<string, object> parameters = null, Action<dynamic> setItem = null)
{
Func<SqlCommand, List<object>> excute = (dbCommand) =>
{
var result = new List<object>(); using (IDataReader dataReader = dbCommand.ExecuteReader())
{
while (dataReader.Read())
{
var item = dataReader.GetReaderData(type);
if (setItem != null)
{
setItem(item);
}
result.Add(item);
}
}
return result;
};
return CreateDbCommondAndExcute<List<object>>(commandText, parameters,
excute);
} /// <summary>
/// 查询对象
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="commandText"></param>
/// <param name="parameters"></param>
/// <param name="excute"></param>
/// <returns></returns>
public T ExecuteReader<T>(string commandText, IDictionary<string, object> parameters = null, Func<IDataReader, T> load = null) where T : class,new()
{
Func<SqlCommand, T> excute = (dbCommand) =>
{
var result = default(T);
using (IDataReader reader = dbCommand.ExecuteReader())
{
while (reader.Read())
{
if (load == null)
{
load = (s) => { return s.GetReaderData<T>(); };
}
result = load(reader);
}
return result;
}
};
return CreateDbCommondAndExcute<T>(commandText, parameters, excute);
} /// <summary>
/// 查询数量
/// </summary>
/// <param name="commandText"></param>
/// <param name="parameters"></param>
/// <returns></returns>
public object ExecuteScalar(string commandText, IDictionary<string, object> parameters = null)
{
Func<SqlCommand, object> excute = (dbCommand) =>
{
return dbCommand.ExecuteScalar();
};
return CreateDbCommondAndExcute(commandText, parameters, excute);
} /// <summary>
/// 创建命令并执行
/// </summary>
/// <typeparam name="TValue"></typeparam>
/// <param name="commandText"></param>
/// <param name="parameters"></param>
/// <param name="excute"></param>
/// <returns></returns>
private TValue CreateDbCommondAndExcute<TValue>(string commandText,
IDictionary<string, object> parameters, Func<SqlCommand, TValue> excute)
{
if (Connection.State == ConnectionState.Closed) { Connection.Open(); };
using (SqlCommand command = new SqlCommand())
{
command.CommandType = CommandType.Text;
command.CommandText = commandText;;
command.Connection = Connection;
command.SetParameters(parameters);
return excute(command);
}
} /// <summary>
/// 关闭连接
/// </summary>
public void Dispose()
{
if (connection != null)
{
Connection.Dispose();//非托管资源
}
}
}

在调用方法时需要注意,一个事务涉及多个聚合时,需要保证传递同一工作单元,并在方法的最后调用Commit() 方法。

public class Services : IService
{
private IMemberRespository member; private IUnitOfWork unitOfWork; public Services(IMemberRespository member, IUnitOfWork unitOfWork)
{
this.member = member;
this.unitOfWork = unitOfWork;
} /// <summary>
/// 测试用例
/// </summary>
public void Demo()
{ member.Test(); unitOfWork.Commit();
}
}

工作单元 — Unit Of Work的更多相关文章

  1. 工作单元(Unit of Work)

    维护受业务事务影响的对象列表,并协调变化的写入和并发问题的解决. 从DB中存取Data时,必须记录增删改动作,以将对DB有影响的数据写会到DB中去. 如果在每次修改对象模型时就对DB进行相应的修改,会 ...

  2. ABP理论学习之工作单元(Unit of Work)

    返回总目录 本篇目录 公共连接和事务管理方法 ABP中的连接和事务管理 仓储类 应用服务 工作单元 工作单元详解 关闭工作单元 非事务的工作单元 工作单元方法调用其它 工作单元作用域 自动保存 IRe ...

  3. 基于DDD的.NET开发框架 - ABP工作单元(Unit of Work)

    返回ABP系列 ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)”的简称. ASP.NET Boilerplate是一个用最佳实践和流行技术开发现代WEB应 ...

  4. 【.Net设计模式系列】工作单元(Unit Of Work)模式 ( 二 )

    回顾 在上一篇博客[.Net设计模式系列]仓储(Repository)模式 ( 一 ) 中,通过各位兄台的评论中,可以看出在设计上还有很多的问题,在这里特别感谢 @横竖都溢 @ 浮云飞梦 2位兄台对博 ...

  5. ABP(现代ASP.NET样板开发框架)系列之12、ABP领域层——工作单元(Unit Of work)

    点这里进入ABP系列文章总目录 基于DDD的现代ASP.NET开发框架--ABP系列之12.ABP领域层——工作单元(Unit Of work) ABP是“ASP.NET Boilerplate Pr ...

  6. ABP领域层——工作单元(Unit Of work)

    ABP领域层——工作单元(Unit Of work) 点这里进入ABP系列文章总目录 基于DDD的现代ASP.NET开发框架--ABP系列之12.ABP领域层——工作单元(Unit Of work) ...

  7. 解析ABP框架中的事务处理和工作单元,ABP事务处理

    通用连接和事务管理方法连接和事务管理是使用数据库的应用程序最重要的概念之一.当你开启一个数据库连接,什么时候开始事务,如何释放连接...诸如此类的. 正如大家都知道的,.Net使用连接池(connec ...

  8. ABP领域层知识回顾之---工作单元

    1. 前言   在上一篇博文中(http://www.cnblogs.com/xiyin/p/6842958.html) 我们讲到了ABP领域层的仓储.这边博文我们来讲 工作单元.个人觉得比较重要.文 ...

  9. [.NET领域驱动设计实战系列]专题四:前期准备之工作单元模式(Unit Of Work)

    一.前言 在前一专题中介绍了规约模式的实现,然后在仓储实现中,经常会涉及工作单元模式的实现.然而,在我的网上书店案例中也将引入工作单元模式,所以本专题将详细介绍下该模式,为后面案例的实现做一个铺垫. ...

随机推荐

  1. 从Maven中央仓库下载jar包

    1. Maven中央仓库 Maven中央仓库存放着比较新版本比较全的 jar 包 仓库网址:https://mvnrepository.com/ 2. 使用Maven中央仓库的 jar 包 (1) 在 ...

  2. 使用hibernate利用实体类生成表和利用表生成实体类

    1,配置数据库,这里以oracle数据库为例.点击右侧Database图标:

  3. C++的精髓——代码复用、接口复用

    C++的精髓——代码复用.接口复用 在另一篇文章中提到C++三大特点的核心概括,也写在这里吧.封装:信息隐藏继承:代码复用多态:面向对象C++并不是面向对象,它包容多种编程思想,如面向过程,面向对象, ...

  4. SQL-W3School-高级:SQL INNER JOIN 关键字

    ylbtech-SQL-W3School-高级:SQL INNER JOIN 关键字 1.返回顶部 1. SQL INNER JOIN 关键字 在表中存在至少一个匹配时,INNER JOIN 关键字返 ...

  5. Session_start的使用

    PHP session用法其实很简单它可以把用户提交的数据以全局变量形式保存在一个session中并且会生成一个唯一的session_id,这样就是为了多了不会产生混乱了,并且session中同一浏览 ...

  6. 002-log-log4j

    一.概述 Log4j是Apache的一个开放源代码项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台.文件.GUI组件.甚至是套接口服务器.NT的事件记录器.UNIX Syslog守护 ...

  7. 阶段5 3.微服务项目【学成在线】_day03 CMS页面管理开发_15-异常处理-异常处理流程

    右侧是框架报的异常 不可预知的,例如数据库连不上这一类的.可以在map中制定某些类的异常,如果找不到就最右边的 99999的, 系统对异常的处理使用统一的异常处理流程: 1.自定义异常类型. 2.自定 ...

  8. SSD总结

    SSD: Single Shot MultiBox Detector 1. Introduction 改进点: 以前的方法都是先搞bounding box,再对box里面做分类.特点:精度高,速度慢. ...

  9. 1-18-2 LVM管理和ssm存储管理器使用&磁盘配额 (二)

    LVM管理和ssm存储管理器使用&磁盘配额  (二) 内容如下: ü  LVM快照 ü  ssm存储管理器的使用 ü  磁盘配额 第1章 LVM快照 lvm快照:为了保持系统的一致性,我们先做 ...

  10. 极客时间-左耳听风-程序员攻略-异步I/O模型和Lock-Free编程

    异步 I/O 模型 异步 I/O 模型其中的设计模式或是解决方法可以借鉴到分布式架构上来. 史蒂文斯(Stevens)在<UNIX 网络编程>一书 6.2 I/O Models 中介绍了五 ...