首页 > 代码库 > 通用EF框架

通用EF框架

  之前我老大去网上找了一个DAL里面操作数据库的通用类:

    public class DALHelper    {        public static List<T> Search<T>() where T : SH_SetBase        {            using (var db = new ShopContext())            {                var dbSet = GetDBSet(db, typeof(T)) as DbSet<T>;                if (typeof(T).IsSubclassOf(typeof(SH_SetBase)))                {                    return dbSet.Where(o => !o.IsDelete).ToList();                }                return dbSet.ToList();            }        }        public static List<T> Search<T>(Expression<Func<T, bool>> where) where T : SH_Base        {            using (ShopContext db = new ShopContext())            {                DbSet<T> dbSet = GetDBSet(db, typeof(T)) as DbSet<T>;                if (typeof(T).IsSubclassOf(typeof(SH_SetBase)))                {                    Expression<Func<T, bool>> where2 = (o => (o as SH_SetBase).IsDelete == false);                    var invokedExpr = Expression.Invoke(where2, where.Parameters.Cast<Expression>());                    Expression<Func<T, bool>> where3 = Expression.Lambda<Func<T, bool>>(Expression.And(where.Body, invokedExpr), where.Parameters);                    return dbSet.Where(where3.Compile()).ToList();                }                return dbSet.Where(where).ToList();            }        }        public static List<T> Search<T>(Expression<Func<T, bool>> where, PageContent pageContent) where T : SH_Base        {            using (ShopContext db = new ShopContext())            {                DbSet<T> dbSet = GetDBSet(db, typeof(T)) as DbSet<T>;                if (typeof(T).IsSubclassOf(typeof(SH_SetBase)))                {                    Expression<Func<T, bool>> where2 = (o => (o as SH_SetBase).IsDelete == false);                    var invokedExpr = Expression.Invoke(where2, where.Parameters.Cast<Expression>());                    Expression<Func<T, bool>> where3 = Expression.Lambda<Func<T, bool>>(Expression.And(where.Body, invokedExpr), where.Parameters);                    where = where3;                }                pageContent.TotalLogs = Count<T>(where);                return dbSet.Where(where.Compile()).Skip((pageContent.PageIndex - 1) * pageContent.PageSize).Take(pageContent.PageSize).ToList();            }        }        public static List<T> Search<T>(Expression<Func<T, object>> include, Expression<Func<T, bool>> where) where T : SH_Base        {            using (ShopContext db = new ShopContext())            {                DbSet<T> dbSet = GetDBSet(db, typeof(T)) as DbSet<T>;                if (typeof(T).IsSubclassOf(typeof(SH_SetBase)))                {                    Expression<Func<T, bool>> where2 = (o => (o as SH_SetBase).IsDelete == false);                    var invokedExpr = Expression.Invoke(where2, where.Parameters.Cast<Expression>());                    Expression<Func<T, bool>> where3 = Expression.Lambda<Func<T, bool>>(Expression.And(where.Body, invokedExpr), where.Parameters);                    return dbSet.Include(include).Where(where3.Compile()).ToList();                }                return dbSet.Include(include).Where(where).ToList();            }        }        public static List<T> Search<T>(Expression<Func<T, object>> include, Expression<Func<T, bool>> where, PageContent pageContent) where T : SH_Base        {            using (ShopContext db = new ShopContext())            {                DbSet<T> dbSet = GetDBSet(db, typeof(T)) as DbSet<T>;                if (typeof(T).IsSubclassOf(typeof(SH_SetBase)))                {                    Expression<Func<T, bool>> where2 = (o => (o as SH_SetBase).IsDelete == false);                    var invokedExpr = Expression.Invoke(where2, where.Parameters.Cast<Expression>());                    Expression<Func<T, bool>> where3 = Expression.Lambda<Func<T, bool>>(Expression.And(where.Body, invokedExpr), where.Parameters);                    where = where3;                }                pageContent.TotalLogs = Count<T>(where);                return dbSet.Include(include).Where(where.Compile()).Skip((pageContent.PageIndex - 1) * pageContent.PageSize).Take(pageContent.PageSize).ToList();            }        }        public static List<T> Search<T>(Expression<Func<T, bool>> where, PageContent pageContent, Expression<Func<T, object>> order, bool isAsc) where T : SH_Base        {            using (ShopContext db = new ShopContext())            {                DbSet<T> dbSet = GetDBSet(db, typeof(T)) as DbSet<T>;                if (typeof(T).IsSubclassOf(typeof(SH_SetBase)))                {                    Expression<Func<T, bool>> where2 = (o => (o as SH_SetBase).IsDelete == false);                    var invokedExpr = Expression.Invoke(where2, where.Parameters.Cast<Expression>());                    Expression<Func<T, bool>> where3 = Expression.Lambda<Func<T, bool>>(Expression.And(where.Body, invokedExpr), where.Parameters);                    where = where3;                }                pageContent.TotalLogs = Count<T>(where);                if (isAsc)                    return dbSet.Where(where.Compile()).OrderBy(order.Compile()).Skip((pageContent.PageIndex - 1) * pageContent.PageSize).Take(pageContent.PageSize).ToList();                else                    return dbSet.Where(where.Compile()).OrderByDescending(order.Compile()).Skip((pageContent.PageIndex - 1) * pageContent.PageSize).Take(pageContent.PageSize).ToList();            }        }        public static List<T> Search<T>(Expression<Func<T, object>> include, Expression<Func<T, bool>> where, PageContent pageContent, Expression<Func<T, object>> order, bool isAsc) where T : SH_Base        {            using (ShopContext db = new ShopContext())            {                DbSet<T> dbSet = GetDBSet(db, typeof(T)) as DbSet<T>;                if (typeof(T).IsSubclassOf(typeof(SH_SetBase)))                {                    Expression<Func<T, bool>> where2 = (o => (o as SH_SetBase).IsDelete == false);                    var invokedExpr = Expression.Invoke(where2, where.Parameters.Cast<Expression>());                    Expression<Func<T, bool>> where3 = Expression.Lambda<Func<T, bool>>(Expression.And(where.Body, invokedExpr), where.Parameters);                    where = where3;                }                pageContent.TotalLogs = Count<T>(where);                if (isAsc)                    return dbSet.Include(include).Where(where.Compile()).OrderBy(order.Compile()).Skip((pageContent.PageIndex - 1) * pageContent.PageSize).Take(pageContent.PageSize).ToList();                else                    return dbSet.Include(include).Where(where.Compile()).OrderByDescending(order.Compile()).Skip((pageContent.PageIndex - 1) * pageContent.PageSize).Take(pageContent.PageSize).ToList();            }        }        public static List<T> Search<T>(Expression<Func<T, object>> path1, Expression<Func<T, object>> path2, Expression<Func<T, bool>> where, PageContent pageContent, Expression<Func<T, object>> order, bool isAsc) where T : SH_Base        {            using (ShopContext db = new ShopContext())            {                DbSet<T> dbSet = GetDBSet(db, typeof(T)) as DbSet<T>;                if (typeof(T).IsSubclassOf(typeof(SH_SetBase)))                {                    Expression<Func<T, bool>> where2 = (o => (o as SH_SetBase).IsDelete == false);                    var invokedExpr = Expression.Invoke(where2, where.Parameters.Cast<Expression>());                    Expression<Func<T, bool>> where3 = Expression.Lambda<Func<T, bool>>(Expression.And(where.Body, invokedExpr), where.Parameters);                    where = where3;                }                pageContent.TotalLogs = Count<T>(where);                if (isAsc)                    return dbSet.Include(path1).Include(path2).Where(where.Compile()).OrderBy(order.Compile()).Skip((pageContent.PageIndex - 1) * pageContent.PageSize).Take(pageContent.PageSize).ToList();                else                    return dbSet.Include(path1).Include(path2).Where(where.Compile()).OrderByDescending(order.Compile()).Skip((pageContent.PageIndex - 1) * pageContent.PageSize).Take(pageContent.PageSize).ToList();            }        }        public static bool Exist<T>(Expression<Func<T, bool>> where) where T : SH_Base        {            using (ShopContext db = new ShopContext())            {                DbSet<T> dbSet = GetDBSet(db, typeof(T)) as DbSet<T>;                if (typeof(T).IsSubclassOf(typeof(SH_SetBase)))                {                    Expression<Func<T, bool>> where2 = (o => (o as SH_SetBase).IsDelete == false);                    var invokedExpr = Expression.Invoke(where2, where.Parameters.Cast<Expression>());                    Expression<Func<T, bool>> where3 = Expression.Lambda<Func<T, bool>>(Expression.And(where.Body, invokedExpr), where.Parameters);                    return dbSet.FirstOrDefault(where3.Compile()) != null;                }                return dbSet.FirstOrDefault(where.Compile()) != null;            }        }        public static int Count<T>(Expression<Func<T, bool>> where) where T : SH_Base        {            using (ShopContext db = new ShopContext())            {                DbSet<T> dbSet = GetDBSet(db, typeof(T)) as DbSet<T>;                if (typeof(T).IsSubclassOf(typeof(SH_SetBase)))                {                    Expression<Func<T, bool>> where2 = (o => (o as SH_SetBase).IsDelete == false);                    var invokedExpr = Expression.Invoke(where2, where.Parameters.Cast<Expression>());                    Expression<Func<T, bool>> where3 = Expression.Lambda<Func<T, bool>>(Expression.And(where.Body, invokedExpr), where.Parameters);                    return dbSet.Count(where3.Compile());                }                return dbSet.Count(where);            }        }        public static decimal Sum<T>(Expression<Func<T, bool>> where, Expression<Func<T, decimal>> selector) where T : SH_Base        {            using (ShopContext db = new ShopContext())            {                DbSet<T> dbSet = GetDBSet(db, typeof(T)) as DbSet<T>;                if (typeof(T).IsSubclassOf(typeof(SH_SetBase)))                {                    Expression<Func<T, bool>> where2 = (o => (o as SH_SetBase).IsDelete == false);                    var invokedExpr = Expression.Invoke(where2, where.Parameters.Cast<Expression>());                    Expression<Func<T, bool>> where3 = Expression.Lambda<Func<T, bool>>(Expression.And(where.Body, invokedExpr), where.Parameters);                    return dbSet.Where(where3.Compile()).Sum(selector.Compile());                }                return dbSet.Where(where.Compile()).Sum(selector.Compile());            }        }        public static int Sum<T>(Expression<Func<T, bool>> where, Expression<Func<T, int>> selector) where T : SH_Base        {            using (ShopContext db = new ShopContext())            {                DbSet<T> dbSet = GetDBSet(db, typeof(T)) as DbSet<T>;                if (typeof(T).IsSubclassOf(typeof(SH_SetBase)))                {                    Expression<Func<T, bool>> where2 = (o => (o as SH_SetBase).IsDelete == false);                    var invokedExpr = Expression.Invoke(where2, where.Parameters.Cast<Expression>());                    Expression<Func<T, bool>> where3 = Expression.Lambda<Func<T, bool>>(Expression.And(where.Body, invokedExpr), where.Parameters);                    return dbSet.Where(where3.Compile()).Sum(selector.Compile());                }                return dbSet.Where(where.Compile()).Sum(selector.Compile());            }        }        public static T SearchObject<T>(Expression<Func<T, bool>> where) where T : SH_Base        {            using (ShopContext db = new ShopContext())            {                DbSet<T> dbSet = GetDBSet(db, typeof(T)) as DbSet<T>;                if (typeof(T).IsSubclassOf(typeof(SH_SetBase)))                {                    Expression<Func<T, bool>> where2 = (o => (o as SH_SetBase).IsDelete == false);                    var invokedExpr = Expression.Invoke(where2, where.Parameters.Cast<Expression>());                    Expression<Func<T, bool>> where3 = Expression.Lambda<Func<T, bool>>(Expression.And(where.Body, invokedExpr), where.Parameters);                    return dbSet.FirstOrDefault(where3.Compile());                }                return dbSet.FirstOrDefault(where.Compile());            }        }        public static T Find<T>(long id) where T : SH_Base        {            using (ShopContext db = new ShopContext())            {                DbSet<T> dbSet = GetDBSet(db, typeof(T)) as DbSet<T>;                if (typeof(T).IsSubclassOf(typeof(SH_SetBase)))                {                    SH_SetBase model = dbSet.Find(id) as SH_SetBase;                    if (model != null && !model.IsDelete)                        return model as T;                }                return dbSet.Find(id) as T;            }        }        public static bool Save(SH_Base model)        {            using (ShopContext db = new ShopContext())            {                object dbSet = GetDBSet(db, model);                if (model.ID == 0)                {                    CallMethod(dbSet, "Add", new object[] { model });                }                else                {                    CallMethod(dbSet, "Attach", new object[] { model });                    db.Entry(model).State = EntityState.Modified;                }                if (model.GetType().IsSubclassOf(typeof(SH_SetBase)))                {                    ((SH_SetBase)model).LastUpdateTime = DateTime.Now;                    ((SH_SetBase)model).IsDelete = false;                }                else                {                    ((SH_LogBase)model).LogTime = DateTime.Now;                }                db.SaveChanges();                return true;            }        }        public static bool Delete(SH_Base model)        {            using (ShopContext db = new ShopContext())            {                if (model.GetType().IsSubclassOf(typeof(SH_SetBase)))                {                    ((SH_SetBase)model).LastUpdateTime = DateTime.Now;                    ((SH_SetBase)model).IsDelete = true;                    db.Entry(model).State = EntityState.Modified;                    db.SaveChanges();                    return true;                }                object dbSet = GetDBSet(db, model);                CallMethod(dbSet, "Remove", new object[] { model });                db.Entry(model).State = EntityState.Modified;                db.SaveChanges();                return true;            }        }        private static object GetDBSet(ShopContext db, SH_Base model)        {            string modelName = ObjectContext.GetObjectType(model.GetType()).Name;            modelName = modelName.Replace("SH_", "");            Type type = db.GetType();            PropertyInfo property = type.GetProperty(modelName);            object dbSet = property.GetValue(db);            return dbSet;        }        private static object GetDBSet(ShopContext db, Type type)        {            type = ObjectContext.GetObjectType(type);            string modelName = type.Name;            modelName = modelName.Replace("SH_", "");            PropertyInfo property = db.GetType().GetProperty(modelName);            object dbSet = property.GetValue(db);            return dbSet;        }        private static object CallMethod(object obj, string methodName, object[] parms)        {            Type type = obj.GetType();            MethodInfo methodInfo = type.GetMethod(methodName);            return methodInfo.Invoke(obj, parms);        }    }

  可以看到里面包含了对SH_SetBase的特殊处理,这个有必要解释一下,因为老大之前的设计是数据库表分为两类,一种是记录表(日志表),他们继承自SH_LogBase,一种是姑且说是对象表吧,他们继承自SH_SetBase,然后全部表继承自SH_Base表,为什么要这样设计呢,其中一个原因是对象表里的数据不能真删除,他们一般是有外键的,级联删除的话删除太多了,而且里面的数据也很重要,只能假删除,所以SH_SetBase得有是否删除IsDelete字段,假删除的话那部分数据是不会再取出来的,除了假删除应该还可以禁用,比如冻结账号,冻结后又可以解冻,这就需要是否启用字段IsEnable字段。

  SH_Base表:

    public class SH_Base    {         /// <summary>        /// 标识,自动增加         /// </summary>        [Key]        public long ID        {            get;            set;        }        /// <summary>        /// 备注        /// </summary>        [Display(Name = "备注")]        public string Summary        {            get;            set;        }    }

  SH_LogBase表:

    public class SH_LogBase : SH_Base    {        private DateTime _logTime = DateTime.Now;        /// <summary>        /// 记录时间,默认当前时间        /// </summary>        [Display(Name = "记录时间")]        public DateTime LogTime        {            get { return _logTime; }            set { _logTime = value; }        }    }

  SH_SetBase表:

    public class SH_SetBase : SH_Base    {        /// <summary>        /// 是否删除,默认未删除        /// </summary>        [Display(Name = "是否删除")]        public bool IsDelete        {            get;            set;        }        private bool _isEnable = true;        /// <summary>        /// 是否启用,默认为启用        /// </summary>        [Display(Name = "是否启用")]        public bool IsEnable        {            get { return _isEnable; }            set { _isEnable = value; }        }        private DateTime _lastUpdateTime = DateTime.Now;        /// <summary>        /// 最后更新时间,默认当前时间        /// </summary>        [Display(Name = "最后更新时间")]        public DateTime LastUpdateTime        {            get { return _lastUpdateTime; }            set { _lastUpdateTime = value; }        }    }

  可我发觉DalHelper太臃肿了,而且里面用到了反射,我一直避免用反射,觉得那货效率比较低。后来看了C#线程内唯一的单例用法。把DalHelper拆分成两个BaseDal和SetBaseDal类,他们继承自IBaseDal类,里面的数据库采用线程内单例模式:

    public class DbContextFactory    {        public static ShopContext GetCurrentDbContext()        {            var db = (ShopContext)CallContext.GetData("ShopContext");            if (db != null) return db;            db = new ShopContext();            CallContext.SetData("ShopContext", db);            return db;        }    }

  接口IBaseDal类:

    interface IBaseDal<T>    {        T Find(long id);        T First(Expression<Func<T, bool>> predicate);        T Add(T entity);        bool Update(T entity);        bool Delete(long id);        bool Delete(T entity);        bool Delete(IEnumerable<T> entities);        bool Exist(Expression<Func<T, bool>> predicate);        int Count(Expression<Func<T, bool>> predicate);        int Sum(Expression<Func<T, bool>> predicate, Expression<Func<T, int>> selector);        decimal Sum(Expression<Func<T, bool>> predicate, Expression<Func<T, decimal>> selector);        IQueryable<T> LoadEntities();        IQueryable<T> LoadEntities(Expression<Func<T, bool>> predicate);        IQueryable<T> LoadPageEntities<TS>(PageContent page, Expression<Func<T, bool>> predicate,            Expression<Func<T, TS>> keySelector, bool isAsc);    }

  日志类使用的BaseDal类:

    public class BaseDal<T> : IBaseDal<T> where T : class , new()    {        public static ShopContext Db        {            get            {                return DbContextFactory.GetCurrentDbContext();            }        }        public virtual T Find(long id)        {            return Db.Set<T>().Find(id);        }        public virtual T First(Expression<Func<T, bool>> predicate)        {            return Db.Set<T>().FirstOrDefault(predicate);        }        public virtual T Add(T entity)        {            Db.Set<T>().Add(entity);            return entity;        }        public virtual bool Update(T entity)        {            Db.Entry(entity).State = EntityState.Modified;            return true;        }        public virtual bool Delete(long id)        {            return Delete(Find(id));        }        public virtual bool Delete(T entity)        {            Db.Set<T>().Remove(entity);            return true;        }        public virtual bool Delete(IEnumerable<T> entities)        {            Db.Set<T>().RemoveRange(entities);            return true;        }        public virtual bool Exist(Expression<Func<T, bool>> predicate)        {            return Db.Set<T>().Any(predicate);        }        public virtual int Count(Expression<Func<T, bool>> predicate)        {            return Db.Set<T>().Count(predicate);        }        public virtual int Sum(Expression<Func<T, bool>> predicate, Expression<Func<T, int>> selector)        {            try            {                return Db.Set<T>().Where(predicate).Sum(selector);            }            catch            {                return 0;            }        }        public virtual decimal Sum(Expression<Func<T, bool>> predicate, Expression<Func<T, decimal>> selector)        {            try            {                return Db.Set<T>().Where(predicate).Sum(selector);            }            catch            {                return 0;            }        }        public virtual IQueryable<T> LoadEntities()        {            return Db.Set<T>().AsQueryable();        }        public virtual IQueryable<T> LoadEntities(Expression<Func<T, bool>> predicate)        {            return Db.Set<T>().Where(predicate).AsQueryable();        }        public virtual IQueryable<T> LoadPageEntities<TS>(PageContent page, Expression<Func<T, bool>> predicate, Expression<Func<T, TS>> keySelector, bool isAsc)        {            page.TotalItems = Count(predicate);            var lst = Db.Set<T>().Where(predicate);            lst = isAsc ? lst.OrderBy(keySelector) : lst.OrderByDescending(keySelector);            return lst.Skip(page.PageSize * (page.PageIndex - 1))                  .Take(page.PageSize)                  .AsQueryable();        }    }

  对象类使用的SetBaseDal类:

    public class SetBaseDal<T> : IBaseDal<T> where T : SH_SetBase, new()    {        public static ShopContext Db        {            get            {                return DbContextFactory.GetCurrentDbContext();            }        }        public virtual T Find(long id)        {            var t = Db.Set<T>().Find(id);            return t.IsDelete ? null : t;        }        public virtual T First(Expression<Func<T, bool>> predicate)        {            return Db.Set<T>().Where(o => !o.IsDelete).FirstOrDefault(predicate);        }        public virtual T Add(T entity)        {            Db.Set<T>().Add(entity);            return entity;        }        public virtual bool Update(T entity)        {            entity.LastUpdateTime = DateTime.Now;            Db.Entry(entity).State = EntityState.Modified;            return true;        }        public virtual bool Delete(long id)        {            return Delete(Find(id));        }        public virtual bool Delete(T entity)        {            entity.IsDelete = true;            entity.LastUpdateTime = DateTime.Now;            Db.Entry(entity).State = EntityState.Modified;            return true;        }        public virtual bool Delete(IEnumerable<T> entities)        {            foreach (var entity in entities)            {                Delete(entity);            }            return true;        }        public virtual bool Exist(Expression<Func<T, bool>> predicate)        {            return Db.Set<T>().Where(o => !o.IsDelete).Any(predicate);        }        public virtual int Count(Expression<Func<T, bool>> predicate)        {            return Db.Set<T>().Where(o => !o.IsDelete).Count(predicate);        }        public virtual int Sum(Expression<Func<T, bool>> predicate, Expression<Func<T, int>> selector)        {            try            {                return Db.Set<T>().Where(predicate).Where(o => !o.IsDelete).Sum(selector);            }            catch            {                return 0;            }        }        public virtual decimal Sum(Expression<Func<T, bool>> predicate, Expression<Func<T, decimal>> selector)        {            try            {                return Db.Set<T>().Where(predicate).Where(o => !o.IsDelete).Sum(selector);            }            catch            {                return 0;            }        }        public virtual IQueryable<T> LoadEntities()        {            return Db.Set<T>().Where(o => !o.IsDelete).AsQueryable();        }        public virtual IQueryable<T> LoadEntities(Expression<Func<T, bool>> predicate)        {            return Db.Set<T>().Where(predicate).Where(o => !o.IsDelete).AsQueryable();        }        public virtual IQueryable<T> LoadPageEntities<TS>(PageContent page, Expression<Func<T, bool>> predicate, Expression<Func<T, TS>> keySelector, bool isAsc)        {            page.TotalItems = Count(predicate);            var lst = Db.Set<T>()                .Where(predicate)                .Where(o => !o.IsDelete);            lst = isAsc ? lst.OrderBy(keySelector) : lst.OrderByDescending(keySelector);            return lst.Skip(page.PageSize * (page.PageIndex - 1))                  .Take(page.PageSize)                  .AsQueryable();        }    }

  里面还有个PageContent类:

    public class PageContent    {        public int PageIndex { get; set; }        public int PageSize { get; set; }        public int TotalItems { get; set; }        public int TotalPages        {            get            {                if (PageSize == 0) return 0;                return (TotalItems + PageSize - 1)/PageSize;            }        }    }

 

  可以看出BaseDal和SetBaseDal之间最大的区别就是BaseDal删除是真删除,SetBaseDal不能真删除,调用删除方法自动执行假删除,而且SetBaseDal获取数据等所有方法都把假删除的数据排除掉了。可能你会问既然假删除的数据都被排除掉了,那他们还有存在的必要吗,当然有必要了,因为除了用户看这些数据,管理人员是可以直接去数据库看的,那就能看到那些被假删除的数据了。

  写好这BaseDal和SetBaseDal类之后,BLL的类就可以继承自这两个类或者不继承,在类里使用者两个类,设计理念我不在行,貌似不建议直接继承Dal的通用类,而是在BLL定义一个接口,然后实现每个表的该接口,并在该类里引用Dal里的通用类,不过我觉得怎么方便就怎么用吧,何必一定要符合设计理念呢。还有贫血模型也是,按照面向对象理念是不能设计为贫血模型的,因为一个对象必须是完整的,里面的属性就像一个对象的血肉肢体,而里面的方法就像一个对象能够进行的活动,缺少了方法的实体类就像是尸体类,光有肢体不能动,可我还是那句话,怎么方便就怎么用吧,为何一定要面向对象呢,而且我认为光有属性也有好处,当我只需要该对象来传值的时候其实是不需要该对象的行为的,这样的话贫血模型加载到内存中占用的内存就少了些了。当然,这只是我的胡言乱语,大神请直接忽视。。。

通用EF框架