工作单元 — Unit Of Work

在进行数据库添加、修改、删除时,为了保证事务的一致性,即操作要么全部成功,要么全部失败。例如银行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}[email protected]{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 - 1) * pagesize + 1, 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 = 0; 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 1;
        }

        /// <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();
        }
    }

原文地址:https://www.cnblogs.com/sylone/p/9497531.html

时间: 2024-11-29 13:49:01

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

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

回顾 在上一篇博客[.Net设计模式系列]仓储(Repository)模式 ( 一 ) 中,通过各位兄台的评论中,可以看出在设计上还有很多的问题,在这里特别感谢 @横竖都溢 @ 浮云飞梦 2位兄台对博文中存在的问题给予指出,并提供出好的解决方案,同时也感谢其他园友的支持.欢迎各位园友对博文中出现的错误或者是设计误区给予指出,一方面防止“误人子弟”,另一方面则可以让大家共同成长. 对于上一篇博客,只是给大家提供了一种对于小型项目数据访问层的一种实现方式,通过Sql语句和传递参数来实现CRUD.并未

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

返回ABP系列 ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)”的简称. ASP.NET Boilerplate是一个用最佳实践和流行技术开发现代WEB应用程序的新起点,它旨在成为一个通用的WEB应用程序框架和项目模板. ABP的官方网站:http://www.aspnetboilerplate.com ABP官方文档:http://www.aspnetboilerplate.com/Pages/Documents Github上的开源项目:http

工作单元(Unit Of Work)模式 ( 二 )

转自 http://www.cnblogs.com/retop/p/5193394.html 理论介绍 在进行数据库添加.修改.删除时,为了保证事务的一致性,即操作要么全部成功,要么全部失败.例如银行A.B两个账户的转账业务.一方失败都会导致事务的不完整性,从而事务回滚.而工作单元模式可以跟踪事务,在操作完成时对事务进行统一提交. 理论参考:http://martinfowler.com/eaaCatalog/unitOfWork.html 具体实践 首先,讲解下设计思想:领域层通过相应的库实现

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

ABP领域层——工作单元(Unit Of work) 点这里进入ABP系列文章总目录 基于DDD的现代ASP.NET开发框架--ABP系列之12.ABP领域层——工作单元(Unit Of work) ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)”的简称. ABP的官方网站:http://www.aspnetboilerplate.com ABP在Github上的开源项目:https://github.com/aspnetboilerplate 通用

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

点这里进入ABP系列文章总目录 基于DDD的现代ASP.NET开发框架--ABP系列之12.ABP领域层——工作单元(Unit Of work) ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)”的简称. ABP的官方网站:http://www.aspnetboilerplate.com ABP在Github上的开源项目:https://github.com/aspnetboilerplate 通用连接和事务管理方法 连接和事务管理是使用数据库的应用程

ABP领域层——工作单元

仓储类,应用服务,[UnitOfWork] ABP开启了一个数据库连接并且在进入到仓储方法时会启用一个事务.因此, 你可以安全地使用连接于仓储方法中.在仓储方法结束后,事务会被提交并且 会释放掉连接.假如仓储方法抛出任何异常,事务会被回滚并且释放掉连接. 在这个模式中,仓储方法是单元性的(一个工作单元unit of work) public class TaskRepository : TestRepositoryBase<ETask, long>, ITaskRepository { pub

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

通用连接和事务管理方法连接和事务管理是使用数据库的应用程序最重要的概念之一.当你开启一个数据库连接,什么时候开始事务,如何释放连接...诸如此类的. 正如大家都知道的,.Net使用连接池(connection pooling).因此,创建一个连接实际上是从连接池中取得一个连接,会这么做是因为创建新连接会有成本.如果没有任何连接存在于连接池中,一个新的连接对象会被创建并且添加到连接池中.当你释放连接,它实际上是将这个连接对象送回到连接池.这并不是实际意义上的释放.这个机制是由.Net所提供的.因此

换个角度说工作单元(Unit Of Work):创建、持有与API调用

看到一些工作单元的介绍,有两种感觉,第一种是很学院,说了等于没说,我估计很多都是没有自己引入到实际的项目中去,第二种是告诉我一种结果,说这就是工作单元,但是没说为什么要这么使用.所以,本篇想要探讨的是:为什么工作单元要这么用.首先,要想将工作单元引入到自己的项目中去,急需要解决的一个问题是:工作单元的生命周期,即: 1:工作单元被谁创建,何时消亡? 2:工作单元被谁们持有? 3:工作单元的 4 个 API( MakeNew.MakeDirty.MakeRemoved.Commit )被谁调用?

MVC+EF 理解和实现仓储模式和工作单元模式

MVC+EF 理解和实现仓储模式和工作单元模式 原文:Understanding Repository and Unit of Work Pattern and Implementing Generic Repository in ASP.NET MVC using Entity Framework 文章介绍 在这篇文章中,我们试着来理解Repository(下文简称仓储)和Unit of Work(下文简称工作单元)模式.同时我们使用ASP.NET MVC和Entity Framework 搭