DDD~基础设施层

回到目录

最近被DDD吸引了阿,在这里感谢一下小佟,呵呵,领域驱动设计是个不错的东西,帮助我们把问题清晰化,这候对于复杂业务逻辑是很重要的,今天这一讲主要说一下DDD中的基础设施层(Infrastructure)是如何被我实现的。

Infrastructure Layer:主要功能是对领域模块进行持久化的,在这个层中你需要把领域对象序列化到指定的元件中,可能是数据库,文件或者内存对象,当然它也要提供从物理元件取出数据到领域模型的功能,这是对应的。

目前的DDD项目结果如下

对于Infrastructure这个层我不去定义接口而是让它去实现Domain层的接口,即一切从领域出发,而Infrastructure只负责具体的数据持久化工作,下面我们主要介绍一下IRepository.cs和IExtensionRepository.cs在Infrastructure层是如何被实现的。

与传统DATA层的区别

一 传统Data层定义接口,为数据为导向,而不是以业务为导。

二 将Repository的方法中添加了领域规约,使它Infrastructure更有目的的去实现。

引入工作单元,使多方法形式一个事务的概念

IUnitOfWork接口也是在domain层实现的,不过在这里我们也介绍一下它的代码

    public interface IUnitOfWork

    {

        /// <summary>

        /// 将操作提交到数据库,

        /// </summary>

        void Save();

        /// <summary>

        /// 是否需要显示进行提交(save())

        /// 默认为false,即在repository方法中自动完成提交,值为true时,表示需要显示调用save()方法

        /// </summary>

        /// <returns></returns>

        bool IsExplicitSubmit { get; set; }

    }

工作单元会有保存save操作和是否显示提交的属性,开发人员可以根据业务情况去选择IsExplicitSubmit的状态,默认是自动提交,如果希望多个方法统一一次提

交,可以将IsExplicitSubmit设为true,然后手动进行save(),这是有助于提升程序性能的。

Infrastructure层的核心代码

    public class DbContextRepository<TEntity> :

        IExtensionRepository<TEntity>

        where TEntity : class

    {

        #region Constructors

        public DbContextRepository(IUnitOfWork db, Action<string> logger)

        {

            iUnitWork = db;

            _Db = (DbContext)db;

            Logger = logger;

            ((IObjectContextAdapter)_Db).ObjectContext.CommandTimeout = 0;

        }



        public DbContextRepository(IUnitOfWork db)

            : this(db, null)

        { }



        #endregion



        #region Properties

        /// <summary>

        /// 数据上下文

        /// </summary>

        protected DbContext _Db { get; private set; }

        /// <summary>

        /// 工作单元上下文,子类可以直接使用它

        /// </summary>

        protected IUnitOfWork iUnitWork { get; set; }



        /// <summary>

        /// Action委托事例,在派生类可以操作它

        /// </summary>

        protected Action<string> Logger { get; private set; }



        /// <summary>

        /// 得到上下文中表对象的所有记录数

        /// 当数据表记录在千万以上时,select count(1) from table

        /// 的速度会受到影响,所以扩展一个方法解决这个问题

        /// </summary>

        /// <param name="queryable"></param>

        /// <param name="db"></param>

        /// <returns></returns>

        public int RecordCount

        {

            get

            {

                return Convert.ToInt32(_Db.Database.SqlQuery<long>(

                    "SELECT ROWCNT FROM SYSINDEXES WHERE ID=OBJECT_ID('" + typeof(TEntity).Name + "') AND INDID<2").First());

            }

        }

        #endregion



        #region Fields

        /// <summary>

        /// 数据总数

        /// </summary>

        int DataTotalCount = 0;



        /// <summary>

        /// 数据总页数

        /// </summary>

        int DataTotalPages = 0;



        /// <summary>

        /// 数据页面大小(每次向数据库提交的记录数)

        /// </summary>

        int DataPageSize = 10000;

        #endregion



        #region IRepository<T> 成员



        public virtual void Insert(TEntity item)

        {

            OnBeforeSaved(new SavedEventArgs(item, SaveAction.Insert));

            _Db.Entry<TEntity>(item);

            _Db.Set<TEntity>().Add(item);

            this.SaveChanges();

            OnAfterSaved(new SavedEventArgs(item, SaveAction.Insert));

        }



        public virtual void Delete(TEntity item)

        {

            OnBeforeSaved(new SavedEventArgs(item, SaveAction.Delete));

            _Db.Set<TEntity>().Attach(item);

            _Db.Set<TEntity>().Remove(item);

            this.SaveChanges();

            OnAfterSaved(new SavedEventArgs(item, SaveAction.Delete));

        }



        public virtual void Update(TEntity item)

        {

            OnBeforeSaved(new SavedEventArgs(item, SaveAction.Update));

            _Db.Set<TEntity>().Attach(item);

            _Db.Entry(item).State = EntityState.Modified;

            this.SaveChanges();

            OnAfterSaved(new SavedEventArgs(item, SaveAction.Update));

        }



        public IQueryable<TEntity> GetModel()

        {

            return _Db.Set<TEntity>().AsNoTracking();//对象无法自动添加到上下文中,因为它是使用 NoTracking 合并选项检索的。请在定义此关系之前,将该实体显式附加到 ObjectContext。

            // return _Db.Set<TEntity>();

        }



        #endregion



        #region IExtensionRepository<T> 成员



        public virtual void Insert(IEnumerable<TEntity> item)

        {

            item.ToList().ForEach(i =>

            {

                _Db.Entry<TEntity>(i);

                _Db.Set<TEntity>().Add(i);

            });

            this.SaveChanges();

        }



        public virtual void Delete(IEnumerable<TEntity> item)

        {

            item.ToList().ForEach(i =>

            {

                _Db.Set<TEntity>().Attach(i);

                _Db.Set<TEntity>().Remove(i);

            });

            this.SaveChanges();

        }



        public virtual void Update(IEnumerable<TEntity> item)

        {

            item.ToList().ForEach(i =>

            {

                _Db.Set<TEntity>().Attach(i);

                _Db.Entry(i).State = EntityState.Modified;

            });

            this.SaveChanges();

        }



        public void Update<T>(Expression<Action<T>> entity) where T : class

        {



            T newEntity = typeof(T).GetConstructor(Type.EmptyTypes).Invoke(null) as T;//建立指定类型的实例

            List<string> propertyNameList = new List<string>();

            MemberInitExpression param = entity.Body as MemberInitExpression;

            foreach (var item in param.Bindings)

            {

                string propertyName = item.Member.Name;

                object propertyValue;

                var memberAssignment = item as MemberAssignment;

                if (memberAssignment.Expression.NodeType == ExpressionType.Constant)

                {

                    propertyValue = (memberAssignment.Expression as ConstantExpression).Value;

                }

                else

                {

                    propertyValue = Expression.Lambda(memberAssignment.Expression, null).Compile().DynamicInvoke();

                }

                typeof(T).GetProperty(propertyName).SetValue(newEntity, propertyValue, null);

                propertyNameList.Add(propertyName);

            }

            _Db.Set<T>().Attach(newEntity);

            _Db.Configuration.ValidateOnSaveEnabled = false;

            var ObjectStateEntry = ((IObjectContextAdapter)_Db).ObjectContext.ObjectStateManager.GetObjectStateEntry(newEntity);

            propertyNameList.ForEach(x => ObjectStateEntry.SetModifiedProperty(x.Trim()));

            this.SaveChanges();

            // ((IObjectContextAdapter)_Db).ObjectContext.Detach(newEntity);

        }



        public TEntity Find(params object[] id)

        {

            return _Db.Set<TEntity>().Find(id);

        }



        public IQueryable<TEntity> GetModel(ISpecification<TEntity> specification)

        {

            return GetModel().Where(specification.SatisfiedBy());

        }



        public IQueryable<TEntity> GetModel(Expression<Func<TEntity, bool>> predicate)

        {

            return GetModel().Where(predicate);

        }



        public IQueryable<TEntity> GetModel<S>(Expression<Func<TEntity, S>> orderByExpression, bool asc)

        {

            Orderable<TEntity> order = new Orderable<TEntity>(this.GetModel());

            if (asc)

                order.Asc(orderByExpression);

            else

                order.Desc(orderByExpression);

            return order.Queryable;

        }



        public TEntity Find(Expression<Func<TEntity, bool>> predicate)

        {

            return GetModel(predicate).FirstOrDefault();

        }



        public TEntity Find(ISpecification<TEntity> specification)

        {

            return GetModel(specification).FirstOrDefault();

        }



        public void BulkInsert(IEnumerable<TEntity> item)

        {

            DataPageProcess(item, (currentItems) =>

            {

                ((IObjectContextAdapter)_Db).ObjectContext.CommandTimeout = 0;//永不超时

                _Db.Database.ExecuteSqlCommand(DoSQL(currentItems, SQLType.Insert));

            });

        }



        public void BulkDelete(IEnumerable<TEntity> item)

        {

            DataPageProcess(item, (currentItems) =>

            {

                ((IObjectContextAdapter)_Db).ObjectContext.CommandTimeout = 0;//永不超时

                _Db.Database.ExecuteSqlCommand(DoSQL(currentItems, SQLType.Delete));

            });

        }



        public void BulkUpdate(IEnumerable<TEntity> item, params string[] fieldParams)

        {

            DataPageProcess(item, (currentItems) =>

            {

                ((IObjectContextAdapter)_Db).ObjectContext.CommandTimeout = 0;//永不超时

                _Db.Database.ExecuteSqlCommand(DoSQL(currentItems, SQLType.Update, fieldParams));

            });

        }



        public void BulkUpdate(IEnumerable<Expression<Action<TEntity>>> expressionList)

        {

            DataPageProcess(expressionList, (currentItems) =>

            {

                StringBuilder sqlstr = new StringBuilder();

                currentItems.ToList().ForEach(i =>

                {

                    Tuple<string, object[]> sql = CreateUpdateSQL(i);

                    sqlstr.AppendFormat(sql.Item1, sql.Item2);

                });

                ((IObjectContextAdapter)_Db).ObjectContext.CommandTimeout = 0;//永不超时

                _Db.Database.ExecuteSqlCommand(sqlstr.ToString());

            });

        }



        public event Action<SavedEventArgs> AfterSaved;



        public event Action<SavedEventArgs> BeforeSaved;



        #endregion



        #region Protected Methods

        /// <summary>

        /// 根据工作单元的IsUnitOfWork的属性,去判断是否提交到数据库

        /// 一般地,在多个repository类型进行组合时,这个IsUnitOfWork都会设为true,即不马上提交,

        /// 而对于单个repository操作来说,它的值不需要设置,使用默认的false,将直接提交到数据库,这也保证了操作的原子性。

        /// </summary>

        protected void SaveChanges()

        {

            try

            {

                if (!iUnitWork.IsExplicitSubmit)// if (iUnitWork.IsUnitOfWork ^ true)

                    iUnitWork.Save();

            }

            catch (System.Data.Entity.Validation.DbEntityValidationException dbEx)

            {

                if (Logger == null)

                    throw dbEx;

                Logger(dbEx.Message);

            }

            catch (Exception ex)

            {

                if (Logger == null)//如果没有定义日志功能,就把异常抛出来吧

                    throw ex;

                Logger(ex.Message);

            }



        }



        /// <summary>

        ///  计数更新,与SaveChange()是两个SQL链接,走分布式事务

        ///  子类可以根据自己的逻辑,去复写

        ///  tableName:表名

        ///  param:索引0为主键名,1表主键值,2为要计数的字段,3为增量

        /// </summary>

        /// <param name="tableName">表名</param>

        /// <param name="param">参数列表,索引0为主键名,1表主键值,2为要计数的字段,3为增量</param>

        protected virtual void UpdateForCount(string tableName, params object[] param)

        {

            string sql = "UPDATE [" + tableName + "] SET [{2}]=ISNULL([{2}],0)+{3} WHERE [{0}]={1}";

            List<object> listParasm = new List<object>

            {

                param[0],

                param[1],

                param[2],

                param[3],

            };

            _Db.Database.ExecuteSqlCommand(string.Format(sql, listParasm.ToArray()));

        }

        #endregion



        #region Virtual Methods



        /// <summary>

        /// Called after data saved

        /// </summary>

        /// <param name="sender">The sender.</param>

        /// <param name="action">The action.</param>

        protected virtual void OnAfterSaved(SavedEventArgs e)

        {

            if (AfterSaved != null)

            {

                AfterSaved(e);

            }

        }



        /// <summary>

        /// Called before saved

        /// </summary>

        /// <param name="sender">The sender.</param>

        /// <param name="action">The action.</param>

        protected virtual void OnBeforeSaved(SavedEventArgs e)

        {

            if (BeforeSaved != null)

            {

                BeforeSaved(e);

            }

        }



        #endregion



        #region Private Methods



        /// <summary>

        /// 分页进行数据提交的逻辑

        /// </summary>

        /// <param name="item">原列表</param>

        /// <param name="method">处理方法</param>

        /// <param name="currentItem">要进行处理的新列表</param>

        private void DataPageProcess(

            IEnumerable<TEntity> item,

            Action<IEnumerable<TEntity>> method)

        {

            if (item != null && item.Count() > 0)

            {

                DataTotalCount = item.Count();

                this.DataTotalPages = item.Count() / DataPageSize;

                if (DataTotalCount % DataPageSize > 0)

                    DataTotalPages += 1;

                for (int pageIndex = 1; pageIndex <= DataTotalPages; pageIndex++)

                {

                    var currentItems = item.Skip((pageIndex - 1) * DataPageSize).Take(DataPageSize).ToList();

                    method(currentItems);

                }

            }

        }



        private void DataPageProcess(

            IEnumerable<Expression<Action<TEntity>>> item,

            Action<IEnumerable<Expression<Action<TEntity>>>> method)

        {

            if (item != null && item.Count() > 0)

            {

                DataTotalCount = item.Count();

                this.DataTotalPages = item.Count() / DataPageSize;

                if (DataTotalCount % DataPageSize > 0)

                    DataTotalPages += 1;

                for (int pageIndex = 1; pageIndex <= DataTotalPages; pageIndex++)

                {

                    var currentItems = item.Skip((pageIndex - 1) * DataPageSize).Take(DataPageSize).ToList();

                    method(currentItems);

                }

            }

        }



        private static string GetEqualStatment(string fieldName, int paramId, Type pkType)

        {

            if (pkType.IsValueType)

                return string.Format("{0} = {1}", fieldName, GetParamTag(paramId));

            return string.Format("{0} = '{1}'", fieldName, GetParamTag(paramId));



        }



        private static string GetParamTag(int paramId)

        {

            return "{" + paramId + "}";

        }



        /// <summary>

        /// 得到实体键EntityKey

        /// </summary>

        /// <typeparam name="TEntity"></typeparam>

        /// <returns></returns>

        protected ReadOnlyMetadataCollection<EdmMember> GetPrimaryKey()

        {

            EntitySetBase primaryKey = ((IObjectContextAdapter)_Db).ObjectContext.GetEntitySet(typeof(TEntity));

            ReadOnlyMetadataCollection<EdmMember> arr = primaryKey.ElementType.KeyMembers;

            return arr;

        }



        /// <summary>

        /// 构建Update语句串

        /// 注意:如果本方法过滤了int,decimal类型更新为0的列,如果希望更新它们需要指定FieldParams参数

        /// </summary>

        /// <param name="entity">实体列表</param>

        /// <param name="fieldParams">要更新的字段</param>

        /// <returns></returns>

        private Tuple<string, object[]> CreateUpdateSQL(Expression<Action<TEntity>> expression)

        {



            TEntity entity = typeof(TEntity).GetConstructor(Type.EmptyTypes).Invoke(null) as TEntity;//建立指定类型的实例

            List<string> propertyNameList = new List<string>();

            MemberInitExpression param = expression.Body as MemberInitExpression;

            foreach (var item in param.Bindings)

            {

                string propertyName = item.Member.Name;

                object propertyValue;

                var memberAssignment = item as MemberAssignment;

                if (memberAssignment.Expression.NodeType == ExpressionType.Constant)

                {

                    propertyValue = (memberAssignment.Expression as ConstantExpression).Value;

                }

                else

                {

                    propertyValue = Expression.Lambda(memberAssignment.Expression, null).Compile().DynamicInvoke();

                }

                typeof(TEntity).GetProperty(propertyName).SetValue(entity, propertyValue, null);

                propertyNameList.Add(propertyName);

            }

            return CreateUpdateSQL(entity, propertyNameList.ToArray());

        }



        /// <summary>

        /// 构建Update语句串

        /// 注意:如果本方法过滤了int,decimal类型更新为0的列,如果希望更新它们需要指定FieldParams参数

        /// </summary>

        /// <param name="entity">实体列表</param>

        /// <param name="fieldParams">要更新的字段</param>

        /// <returns></returns>

        private Tuple<string, object[]> CreateUpdateSQL(TEntity entity, params string[] fieldParams)

        {

            if (entity == null)

                throw new ArgumentException("The database entity can not be null.");

            List<string> pkList = GetPrimaryKey().Select(i => i.Name).ToList();



            Type entityType = entity.GetType();

            List<PropertyInfo> tableFields = new List<PropertyInfo>();

            if (fieldParams != null && fieldParams.Count() > 0)

            {

                tableFields = entityType.GetProperties().Where(i => fieldParams.Contains(i.Name, new StringComparisonIgnoreCase())).ToList();

            }

            else

            {

                tableFields = entityType.GetProperties().Where(i =>

                              !pkList.Contains(i.Name)

                              && i.GetValue(entity, null) != null

                              && !(i.PropertyType == typeof(ValueType) && Convert.ToInt64(i.GetValue(entity, null)) == 0)

                              && !(i.PropertyType == typeof(DateTime) && Convert.ToDateTime(i.GetValue(entity, null)) == DateTime.MinValue)

                              && i.PropertyType != typeof(EntityState)

                              && !(i.GetCustomAttributes(false).Length > 0

                              && i.GetCustomAttributes(false).Where(j => j.GetType() == typeof(NavigationAttribute)) != null)//过滤导航属性

                              && (i.PropertyType.IsValueType || i.PropertyType == typeof(string))

                               ).ToList();

            }









            //过滤主键,航行属性,状态属性等

            if (pkList == null || pkList.Count == 0)

                throw new ArgumentException("The Table entity have not a primary key.");

            List<object> arguments = new List<object>();

            StringBuilder builder = new StringBuilder();



            foreach (var change in tableFields)

            {

                if (pkList.Contains(change.Name))

                    continue;

                if (arguments.Count != 0)

                    builder.Append(", ");

                builder.Append(change.Name + " = {" + arguments.Count + "}");

                if (change.PropertyType == typeof(string)

                    || change.PropertyType == typeof(DateTime)

                    || change.PropertyType == typeof(Nullable<DateTime>))

                    arguments.Add("'" + change.GetValue(entity, null).ToString().Replace("'", "char(39)") + "'");

                else

                    arguments.Add(change.GetValue(entity, null));

            }



            if (builder.Length == 0)

                throw new Exception("没有任何属性进行更新");



            builder.Insert(0, " UPDATE " + string.Format("[{0}]", entityType.Name) + " SET ");



            builder.Append(" WHERE ");

            bool firstPrimaryKey = true;



            foreach (var primaryField in pkList)

            {

                if (firstPrimaryKey)

                    firstPrimaryKey = false;

                else

                    builder.Append(" AND ");



                object val = entityType.GetProperty(primaryField).GetValue(entity, null);

                Type pkType = entityType.GetProperty(primaryField).GetType();

                builder.Append(GetEqualStatment(primaryField, arguments.Count, pkType));

                arguments.Add(val);

            }

            return new Tuple<string, object[]>(builder.ToString(), arguments.ToArray());



        }



        /// <summary>

        /// 构建Delete语句串

        /// </summary>

        /// <typeparam name="TEntity"></typeparam>

        /// <param name="entity"></param>

        /// <returns></returns>

        private Tuple<string, object[]> CreateDeleteSQL(TEntity entity)

        {

            if (entity == null)

                throw new ArgumentException("The database entity can not be null.");



            Type entityType = entity.GetType();

            List<string> pkList = GetPrimaryKey().Select(i => i.Name).ToList();

            if (pkList == null || pkList.Count == 0)

                throw new ArgumentException("The Table entity have not a primary key.");



            List<object> arguments = new List<object>();

            StringBuilder builder = new StringBuilder();

            builder.Append(" Delete from " + string.Format("[{0}]", entityType.Name));



            builder.Append(" WHERE ");

            bool firstPrimaryKey = true;



            foreach (var primaryField in pkList)

            {

                if (firstPrimaryKey)

                    firstPrimaryKey = false;

                else

                    builder.Append(" AND ");



                Type pkType = entityType.GetProperty(primaryField).GetType();

                object val = entityType.GetProperty(primaryField).GetValue(entity, null);

                builder.Append(GetEqualStatment(primaryField, arguments.Count, pkType));

                arguments.Add(val);

            }

            return new Tuple<string, object[]>(builder.ToString(), arguments.ToArray());

        }



        /// <summary>

        /// 构建Insert语句串

        /// 主键为自增时,如果主键值为0,我们将主键插入到SQL串中

        /// </summary>

        /// <typeparam name="TEntity"></typeparam>

        /// <param name="entity"></param>

        /// <returns></returns>

        private Tuple<string, object[]> CreateInsertSQL(TEntity entity)

        {

            if (entity == null)

                throw new ArgumentException("The database entity can not be null.");



            Type entityType = entity.GetType();

            var table = entityType.GetProperties().Where(i => i.PropertyType != typeof(EntityKey)

                 && i.PropertyType != typeof(EntityState)

                 && i.Name != "IsValid"

                 && i.GetValue(entity, null) != null

                 && !(i.GetCustomAttributes(false).Length > 0

                 && i.GetCustomAttributes(false).Where(j => j.GetType() == typeof(NavigationAttribute)) != null)

                 && (i.PropertyType.IsValueType || i.PropertyType == typeof(string))).ToArray();//过滤主键,航行属性,状态属性等



            List<string> pkList = GetPrimaryKey().Select(i => i.Name).ToList();

            List<object> arguments = new List<object>();

            StringBuilder fieldbuilder = new StringBuilder();

            StringBuilder valuebuilder = new StringBuilder();



            fieldbuilder.Append(" INSERT INTO " + string.Format("[{0}]", entityType.Name) + " (");



            foreach (var member in table)

            {

                if (pkList.Contains(member.Name) && Convert.ToString(member.GetValue(entity, null)) == "0")

                    continue;

                object value = member.GetValue(entity, null);

                if (value != null)

                {

                    if (arguments.Count != 0)

                    {

                        fieldbuilder.Append(", ");

                        valuebuilder.Append(", ");

                    }



                    fieldbuilder.Append(member.Name);

                    if (member.PropertyType == typeof(string)

                        || member.PropertyType == typeof(DateTime)

                        || member.PropertyType == typeof(Nullable<DateTime>)

                        )

                        valuebuilder.Append("'{" + arguments.Count + "}'");

                    else

                        valuebuilder.Append("{" + arguments.Count + "}");

                    if (value.GetType() == typeof(string))

                        value = value.ToString().Replace("'", "char(39)");

                    arguments.Add(value);



                }

            }





            fieldbuilder.Append(") Values (");



            fieldbuilder.Append(valuebuilder.ToString());

            fieldbuilder.Append(");");

            return new Tuple<string, object[]>(fieldbuilder.ToString(), arguments.ToArray());

        }



        /// <summary>

        /// /// <summary>

        /// 执行SQL,根据SQL操作的类型

        /// </summary>

        /// <typeparam name="TEntity"></typeparam>

        /// <param name="list"></param>

        /// <param name="sqlType"></param>

        /// <returns></returns>

        /// </summary>

        /// <param name="list"></param>

        /// <param name="sqlType"></param>

        /// <returns></returns>

        private string DoSQL(IEnumerable<TEntity> list, SQLType sqlType)

        {

            return DoSQL(list, sqlType, null);

        }

        /// <summary>

        /// 执行SQL,根据SQL操作的类型

        /// </summary>

        /// <typeparam name="TEntity"></typeparam>

        /// <param name="list"></param>

        /// <param name="sqlType"></param>

        /// <returns></returns>

        private string DoSQL(IEnumerable<TEntity> list, SQLType sqlType, params string[] fieldParams)

        {

            StringBuilder sqlstr = new StringBuilder();

            switch (sqlType)

            {

                case SQLType.Insert:

                    list.ToList().ForEach(i =>

                    {

                        Tuple<string, object[]> sql = CreateInsertSQL(i);

                        sqlstr.AppendFormat(sql.Item1, sql.Item2);

                    });

                    break;

                case SQLType.Update:

                    list.ToList().ForEach(i =>

                    {

                        Tuple<string, object[]> sql = CreateUpdateSQL(i, fieldParams);

                        sqlstr.AppendFormat(sql.Item1, sql.Item2);

                    });

                    break;

                case SQLType.Delete:

                    list.ToList().ForEach(i =>

                    {

                        Tuple<string, object[]> sql = CreateDeleteSQL(i);

                        sqlstr.AppendFormat(sql.Item1, sql.Item2);

                    });

                    break;

                default:

                    throw new ArgumentException("请输入正确的参数");

            }

            return sqlstr.ToString();

        }



        /// <summary>

        /// SQL操作类型

        /// </summary>

        protected enum SQLType

        {

            /// <summary>

            /// 更新传入的实体代码去添加

            /// </summary>

            Insert,

            /// <summary>

            /// 根据传入的实体列表去更新

            /// </summary>

            Update,

            /// <summary>

            /// 根据传入的实体列表去删除

            /// </summary>

            Delete,

        }

        #endregion

    }

下面看一下对于基础设施层所依赖的程序集

可以看到,它主要依赖于领域实体层与领域实体规约层。

OK,对于基础设施层的搭建就说到这,下回我们将说一下领域层的搭建。

回到目录

你可能感兴趣的:(基础)