通用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;
        }
    }

  或許有些同志會好奇線程內單例模式有什么好處或者什么用,我這里簡單做個測試:

        public static ShopContext GetCurrentDbContext()
        {
            //單例模式:保證線程實例唯一
            var db = (ShopContext)CallContext.GetData("ShopContext");
            if (db != null)
            {
                File.AppendAllText("E:\\ShopDb.txt", Thread.CurrentThread.ManagedThreadId + "");
                return db;
            }
            File.AppendAllText("E:\\ShopDb.txt", Environment.NewLine + Thread.CurrentThread.ManagedThreadId + "");
            db = new ShopContext();
            CallContext.SetData("ShopContext", db);
            return db;
        }

  然后運行網站程序,隨便亂點打開ShopDb.txt一看

可以看出我每點一次網頁鏈接,控制器的Action接收到請求后就會新建一個線程來處理這次請求,由於我在該線程內一直沒有另開線程,所以看到的生成的文件內每次請求就會產生一個新的ShopContext,在單次網頁請求內用的都是同一個ShopContext的,這樣你可能會說有問題呀,單次網頁請求共用一個ShopContext,要是某次數據庫請求太耗時,難道后續的操作要一直等待嗎,這個問題確實存在,解決的辦法就是數據庫請求采用異步請求,單個線程共用ShopContext有個好處就是單次請求內只需新建一次ShopContext,不用老在內存中新建這個對象,這樣的話可能你會說像線程池一樣,搞個ShopContext池不是更好嗎,線程要的時候去池中取一個ShopContext出來,不用的時候歸還給池,這樣ShopContext在內存中新建銷毀的次數就可以達到最少次數了,這個我就不研究下去了。

  接口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);
        }

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

  對象類使用的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);
        }

        public virtual IQueryable<T> LoadEntities(Expression<Func<T, bool>> predicate)
        {
            return Db.Set<T>().Where(predicate).Where(o => !o.IsDelete);
        }

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

  里面還有個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里的通用類,不過我覺得怎么方便就怎么用吧,何必一定要符合設計理念呢。還有貧血模型也是,按照面向對象理念是不能設計為貧血模型的,因為一個對象必須是完整的,里面的屬性就像一個對象的血肉肢體,而里面的方法就像一個對象能夠進行的活動,缺少了方法的實體類就像是屍體類,光有肢體不能動,可我還是那句話,怎么方便就怎么用吧,為何一定要面向對象呢,而且我認為光有屬性也有好處,當我只需要該對象來傳值的時候其實是不需要該對象的行為的,這樣的話貧血模型加載到內存中占用的內存就少了些了。當然,這只是我的胡言亂語,大神請直接忽視。。。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM