• EF架构~基于EF数据层的实现


    回到目录

    之前写过关于实现一个完整的EF架构的文章,文章的阅读量也是满大的,自己很欣慰,但是,那篇文章是我2011年写的,所以,技术有些不成熟,所以今天把我的2014年写的EF底层架构公开一下,这个架构比2011年的有了很大程度的提高,主要在接口规范,查询规范上,并引入了排序功能,两步对完善了EF对数据的批量操作,可以说,这次的架构是很有看点的。

    一 一个基础操作接口

        /// <summary>
        /// 基础的数据操作规范
        /// 与ORM架构无关
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        public interface IRepository<TEntity>
               where TEntity : class
        {
            /// <summary>
            /// 设定数据上下文,它一般由构架方法注入
            /// </summary>
            /// <param name="unitOfWork"></param>
            void SetDbContext(IUnitOfWork unitOfWork);
    
            /// <summary>
            /// 添加实体并提交到数据服务器
            /// </summary>
            /// <param name="item">Item to add to repository</param>
            void Insert(TEntity item);
    
            /// <summary>
            /// 移除实体并提交到数据服务器
            /// 如果表存在约束,需要先删除子表信息
            /// </summary>
            /// <param name="item">Item to delete</param>
            void Delete(TEntity item);
    
            /// <summary>
            /// 修改实体并提交到数据服务器
            /// </summary>
            /// <param name="item"></param>
            void Update(TEntity item);
    
            /// <summary>
            /// 得到指定的实体集合(延时结果集)
            /// Get all elements of type {T} in repository
            /// </summary>
            /// <returns>List of selected elements</returns>
            IQueryable<TEntity> GetModel();
    
            /// <summary>
            /// 根据主键得到实体
            /// </summary>
            /// <param name="id"></param>
            /// <returns></returns>
            TEntity Find(params object[] id);
        }
    View Code

    二 一个扩展操作接口

        /// <summary>
        /// 扩展的Repository操作规范
        /// </summary>
        public interface IExtensionRepository<TEntity> :
            IRepository<TEntity>,
            IOrderableRepository<TEntity>
            where TEntity : class
        {
            /// <summary>
            /// 添加集合[集合数目不大时用此方法,超大集合使用BulkInsert]
            /// </summary>
            /// <param name="item"></param>
            void Insert(IEnumerable<TEntity> item);
    
            /// <summary>
            /// 修改集合[集合数目不大时用此方法,超大集合使用BulkUpdate]
            /// </summary>
            /// <param name="item"></param>
            void Update(IEnumerable<TEntity> item);
    
            /// <summary>
            /// 删除集合[集合数目不大时用此方法,超大集合使用批量删除]
            /// </summary>
            /// <param name="item"></param>
            void Delete(IEnumerable<TEntity> item);
    
            /// <summary>
            /// 扩展更新方法,只对EF支持
            /// 注意本方法不能和GetModel()一起使用,它的表主键可以通过post或get方式获取
            /// </summary>
            /// <param name="entity"></param>
            void Update<T>(Expression<Action<T>> entity) where T : class;
    
            /// <summary>
            /// 根据指定lambda表达式,得到延时结果集
            /// </summary>
            /// <param name="predicate"></param>
            /// <returns></returns>
            IQueryable<TEntity> GetModel(Expression<Func<TEntity, bool>> predicate);
    
            /// <summary>
            /// 根据指定lambda表达式,得到第一个实体
            /// </summary>
            /// <param name="predicate"></param>
            /// <returns></returns>
            TEntity Find(Expression<Func<TEntity, bool>> predicate);
    
            /// <summary>
            /// 批量添加,添加之前可以去除自增属性,默认不去除
            /// </summary>
            /// <param name="item"></param>
            /// <param name="isRemoveIdentity"></param>
            void BulkInsert(IEnumerable<TEntity> item, bool isRemoveIdentity);
    
            /// <summary>
            /// 批量添加
            /// </summary>
            /// <param name="item"></param>
            void BulkInsert(IEnumerable<TEntity> item);
    
            /// <summary>
            /// 批量更新
            /// </summary>
            /// <param name="item"></param>
            void BulkUpdate(IEnumerable<TEntity> item, params string[] fieldParams);
    
            /// <summary>
            /// 批量删除
            /// </summary>
            /// <param name="item"></param>
            void BulkDelete(IEnumerable<TEntity> item);
    
    
        }
    View Code

    三 一个排序操作接口

        /// <summary>
        /// 提供排序功能的规范
        /// </summary>
        public interface IOrderableRepository<TEntity> where TEntity : class
        {
            /// <summary>
            /// 带排序的结果集
            /// </summary>
            /// <param name="orderBy"></param>
            /// <returns></returns>
            IQueryable<TEntity> GetModel(Action<IOrderable<TEntity>> orderBy);
    
    
            /// <summary>
            /// 根据指定lambda表达式和排序方式,得到延时结果集
            /// </summary>
            /// <param name="predicate"></param>
            /// <returns></returns>
            IQueryable<TEntity> GetModel(Action<IOrderable<TEntity>> orderBy, Expression<Func<TEntity, bool>> predicate);
        }
    View Code

    四 基于ef架构的规约查询接口

    /// <summary>
        /// EF底层构架,关于规约功能的仓储接口
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        public interface ISpecificationRepository<TEntity> :
            IExtensionRepository<TEntity>
            where TEntity : class
        {
            /// <summary>
            /// 根据指定规约,得到延时结果集
            /// </summary>
            /// <param name="specification"></param>
            /// <returns></returns>
            IQueryable<TEntity> GetModel(ISpecification<TEntity> specification);
    
            /// <summary>
            /// 根据指定规约,得到第一个实体
            /// </summary>
            /// <param name="specification"></param>
            /// <returns></returns>
            TEntity Find(ISpecification<TEntity> specification);
    
            /// <summary>
            /// 带排序功能的,根据指定规约,得到结果集
            /// </summary>
            /// <param name="orderBy"></param>
            /// <param name="specification"></param>
            /// <returns></returns>
            IQueryable<TEntity> GetModel(Action<IOrderable<TEntity>> orderBy, EntityFrameworks.Entity.Core.Specification.ISpecification<TEntity> specification);
    
            /// <summary>
            /// 保存之后触发
            /// Occurs after data saved
            /// </summary>
            event Action<SavedEventArgs> AfterSaved;
    
            /// <summary>
            /// 保存之前触发
            /// Occurs before data saved
            /// </summary>
            event Action<SavedEventArgs> BeforeSaved;
        }
    View Code

    五 基于工作单元的标识接口

    /// <summary>
        /// 数据上下文标识接口,它对于业务层应该是公开的
        /// 它对于实现上下文的方法,它并不关心,可以是linq2sql,ef,ado.net,nhibernate,memory,nosql等
        /// </summary>
        public interface IUnitOfWork
        {
        }
    View Code

    六 基于ef的DbContext上下文的仓储的实现

     /// <summary>
        /// DbContext上下文仓储功能类,领域上下文可以直接继承它
        /// 生命周期:数据上下文的生命周期为一个HTTP请求的结束
        /// 相关说明:
        /// 1 领域对象使用声明IRepository和IExtensionRepository接口得到不同的操作规范
        /// 2 可以直接为上下注入Action<string>的委托实例,用来记录savechanges产生的异常
        /// 3 可以订阅BeforeSaved和AfterSaved两个事件,用来在方法提交前与提交后实现代码注入
        /// 4 所有领域db上下文都要继承iUnitWork接口,用来实现工作单元,这对于提升程序性能与为重要
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        public class DbContextRepository<TEntity> :
             ISpecificationRepository<TEntity>
             where TEntity : class
        {
            #region Constructors
    
            public DbContextRepository(IUnitOfWork db, Action<string> logger)
            {
                UnitWork = 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 UnitWork { get; set; }
    
            /// <summary>
            /// Action委托事例,在派生类可以操作它
            /// </summary>
            protected Action<string> Logger { get; private set; }
            #endregion
    
            #region Fields
            /// <summary>
            /// 数据总数
            /// </summary>
            int _dataTotalCount = 0;
    
            /// <summary>
            /// 数据总页数
            /// </summary>
            int _dataTotalPages = 0;
    
            /// <summary>
            /// 数据页面大小(每次向数据库提交的记录数)
            /// </summary>
            private const int DataPageSize = 10000;
    
            #endregion
    
            #region Delegates & Event
            /// <summary>
            /// 保存之后
            /// </summary>
            public event Action<SavedEventArgs> AfterSaved;
            /// <summary>
            /// 保存之前
            /// </summary>
            public event Action<SavedEventArgs> BeforeSaved;
            #endregion
    
            #region IRepository<TEntity> 成员
    
            public void SetDbContext(IUnitOfWork unitOfWork)
            {
                this.Db = (DbContext)unitOfWork;
                this.UnitWork = unitOfWork;
            }
    
            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;
                try
                {
                    this.SaveChanges();
                }
                catch (System.Data.OptimisticConcurrencyException ex)//并发冲突异常
                {
    
                    ((IObjectContextAdapter)Db).ObjectContext.Refresh(RefreshMode.ClientWins, item);
                    this.SaveChanges();
                }
    
                OnAfterSaved(new SavedEventArgs(item, SaveAction.Update));
            }
    
            /// <summary>
            /// 子类在实现时,可以重写,加一些状态过滤
            /// </summary>
            /// <returns></returns>
            public virtual IQueryable<TEntity> GetModel()
            {
                //  return Db.Set<TEntity>().AsNoTracking();//对象无法自动添加到上下文中,因为它是使用 NoTracking 合并选项检索的。请在定义此关系之前,将该实体显式附加到 ObjectContext。
                return Db.Set<TEntity>();////ObjectStateManager 中已存在具有同一键的对象。ObjectStateManager 无法跟踪具有相同键的多个对象。
            }
            /// <summary>
            /// 得到原生态结果集
            /// </summary>
            /// <returns></returns>
            public IQueryable<TEntity> GetEntities()
            {
                return Db.Set<TEntity>();
            }
            #endregion
    
            #region IExtensionRepository<TEntity> 成员
    
            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;
                });
                try
                {
                    this.SaveChanges();
                }
                catch (System.Data.OptimisticConcurrencyException ex)//并发冲突异常
                {
    
                    ((IObjectContextAdapter)Db).ObjectContext.Refresh(RefreshMode.ClientWins, item);
                    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);
                }
    
                try
                {
                    Db.Set<T>().Attach(newEntity);
                }
                catch (Exception)
                {
                    throw new Exception("本方法不能和GetModel()一起使用,请使用Update(TEntity entity)方法");
                }
    
                Db.Configuration.ValidateOnSaveEnabled = false;
                var ObjectStateEntry = ((IObjectContextAdapter)Db).ObjectContext.ObjectStateManager.GetObjectStateEntry(newEntity);
                propertyNameList.ForEach(x => ObjectStateEntry.SetModifiedProperty(x.Trim()));
    
                try
                {
                    this.SaveChanges();
    
                }
                catch (System.Data.OptimisticConcurrencyException ex)//并发冲突异常
                {
    
                    ((IObjectContextAdapter)Db).ObjectContext.Refresh(RefreshMode.ClientWins, newEntity);
                    this.SaveChanges();
                }
            }
    
            public TEntity Find(params object[] id)
            {
                return Db.Set<TEntity>().Find(id);
            }
    
            public IQueryable<TEntity> GetModel(Expression<Func<TEntity, bool>> predicate)
            {
                return GetModel().Where(predicate);
            }
    
            public TEntity Find(Expression<Func<TEntity, bool>> predicate)
            {
                return GetModel(predicate).FirstOrDefault();
            }
    
            public void BulkInsert(IEnumerable<TEntity> item)
            {
                BulkInsert(item, false);
            }
    
            public void BulkInsert(IEnumerable<TEntity> item, bool isRemoveIdentity)
            {
                string startTag = "", endTag = "";
                if (isRemoveIdentity)
                {
                    startTag = "SET IDENTITY_INSERT " + typeof(TEntity).Name + " ON;";
                    endTag = "SET IDENTITY_INSERT " + typeof(TEntity).Name + "  OFF;";
                }
                DataPageProcess(item, (currentItems) =>
                {
                    ((IObjectContextAdapter)Db).ObjectContext.CommandTimeout = 0;//永不超时
                    Db.Database.ExecuteSqlCommand(startTag
                        + DoSql(currentItems, SqlType.Insert)
                        + endTag);
                });
            }
    
            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));
                });
            }
    
            #endregion
    
            #region ISpecificationRepository<TEntity> 成员
    
            public TEntity Find(ISpecification<TEntity> specification)
            {
                return GetModel(specification).FirstOrDefault();
            }
    
            public IQueryable<TEntity> GetModel(Action<IOrderable<TEntity>> orderBy, ISpecification<TEntity> specification)
            {
                var linq = new Orderable<TEntity>(GetModel(specification));
                orderBy(linq);
                return linq.Queryable;
            }
    
            public IQueryable<TEntity> GetModel(ISpecification<TEntity> specification)
            {
                return GetModel().Where(specification.SatisfiedBy());
            }
    
            #endregion
    
            #region IOrderableRepository<TEntity>成员
            public IQueryable<TEntity> GetModel(Action<IOrderable<TEntity>> orderBy)
            {
                var linq = new Orderable<TEntity>(GetModel());
                orderBy(linq);
                return linq.Queryable;
            }
    
            public IQueryable<TEntity> GetModel(Action<IOrderable<TEntity>> orderBy, Expression<Func<TEntity, bool>> predicate)
            {
                var linq = new Orderable<TEntity>(GetModel(predicate));
                orderBy(linq);
                return linq.Queryable;
            }
            #endregion
    
            #region Protected Methods
            /// <summary>
            /// 根据工作单元的IsNotSubmit的属性,去判断是否提交到数据库
            /// 一般地,在多个repository类型进行组合时,这个IsNotSubmit都会设为true,即不马上提交,
            /// 而对于单个repository操作来说,它的值不需要设置,使用默认的false,将直接提交到数据库,这也保证了操作的原子性。
            /// </summary>
            protected void SaveChanges()
            {
                try
                {
                    Db.SaveChanges();
                }
                catch (System.Data.Entity.Validation.DbEntityValidationException dbEx)//捕获实体验证异常
                {
                    var sb = new StringBuilder();
                    dbEx.EntityValidationErrors.First().ValidationErrors.ToList().ForEach(i =>
                    {
                        sb.AppendFormat("属性为:{0},信息为:{1}
    
    ", i.PropertyName, i.ErrorMessage);
                    });
                    if (Logger == null)
                        throw new Exception(sb.ToString());
                    Logger(sb.ToString() + "处理时间:" + DateTime.Now);
    
                }
                catch (System.Data.OptimisticConcurrencyException ex)//并发冲突异常
                {
                    //保持数据源中对象的现有属性
                    //Db.Refresh(RefreshMode.StoreWins, person);
                    //  Db.SaveChanges();
                }
                catch (Exception ex)//捕获所有异常
                {
                    if (Logger == null)//如果没有定义日志功能,就把异常抛出来吧
                        throw new Exception(ex.Message);
                    Logger(ex.Message + "处理时间:" + DateTime.Now);
                }
    
            }
    
            /// <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}";
                var 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="e"></param>
            protected virtual void OnAfterSaved(SavedEventArgs e)
            {
                if (AfterSaved != null)
                {
                    AfterSaved(e);
                }
            }
    
            /// <summary>
            /// Called before saved
            /// </summary>
            /// <param name="e"></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.Any())
                {
                    _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));
                if (primaryKey == null)
                    return null;
                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(TEntity entity, params string[] fieldParams)
            {
                if (entity == null)
                    throw new ArgumentException("The database entity can not be null.");
                var pkList = GetPrimaryKey().Select(i => i.Name).ToList();
    
                var entityType = entity.GetType();
                var 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.IsEnum
                                  && !(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).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.");
                var arguments = new List<object>();
                var 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(DateTime?)
                        || change.PropertyType == typeof(bool?)
                        || change.PropertyType == typeof(bool))
                        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.");
    
                var arguments = new List<object>();
                var 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.PropertyType.IsEnum
                     && i.GetCustomAttributes(false).Where(j => j.GetType() == typeof(NavigationAttribute)) != null
                     && (i.PropertyType.IsValueType || i.PropertyType == typeof(string))).ToArray();//过滤主键,航行属性,状态属性等
    
                var pkList = new List<string>();
                if (GetPrimaryKey() != null)//有时主键可能没有设计,这对于添加操作是可以的
                    pkList = GetPrimaryKey().Select(i => i.Name).ToList();
                var arguments = new List<object>();
                var fieldbuilder = new StringBuilder();
                var 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(DateTime?)
                            || member.PropertyType == typeof(Boolean?)
                            || member.PropertyType == typeof(Boolean)
                            )
                            valuebuilder.Append("'{" + arguments.Count + "}'");
                        else
                            valuebuilder.Append("{" + arguments.Count + "}");
                        if (value is 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)
            {
                var 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
            {
                Insert,
                Update,
                Delete,
            }
            #endregion
    
        }
    View Code

    以上六大部分就是我最新的EF架构的核心了,事实上,EF只是实现数据持久化的一种方式,在我的架构中还提到了XmlRepository,RedisRepository,Linq2SqlRepository等等,对于仓储这块感兴趣的同学,可以与我一起去讨论!我很希望有一天,我的底层

    架构有这样一个功能,那就是自动去选择我的数据库,如我的数据库有db1,db2.....dbN,它们之间的数据是同步的(集群),我能通过EF来实现我用哪台数据服务器,想想就很美,哈哈!

    回到目录

  • 相关阅读:
    document.body.clientHeight 和 document.documentElement.clientHeight 的区别
    Javascript操作div及其内含对象示例
    面向对象分析设计的经验原则
    翻页控件示例代码
    C#的6种常用集合类示例
    UML基础知识
    重温OSI和TCP/IP网络分层
    设计模式总结
    活用设计模式
    GridView当数据源为空时仍显示表头
  • 原文地址:https://www.cnblogs.com/lori/p/4040951.html
Copyright © 2020-2023  润新知