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

通用EF框架

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
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>> wherewhere 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>> wherewhere 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>> wherewhere 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>> wherewhere 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>> wherewhere 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里的通用类,不过我觉得怎么方便就怎么用吧,何必一定要符合设计理念呢。还有贫血模型也是,按照面向对象理念是不能设计为贫血模型的,因为一个对象必须是完整的,里面的属性就像一个对象的血肉肢体,而里面的方法就像一个对象能够进行的活动,缺少了方法的实体类就像是尸体类,光有肢体不能动,可我还是那句话,怎么方便就怎么用吧,为何一定要面向对象呢,而且我认为光有属性也有好处,当我只需要该对象来传值的时候其实是不需要该对象的行为的,这样的话贫血模型加载到内存中占用的内存就少了些了。当然,这只是我的胡言乱语,大神请直接忽视。。。

通用EF框架