解決 EF where (func) 查詢的一個性能問題


前兩年幫朋友 做了個網吧管理軟件,采用動軟的三層架構 sql語句生成的。最近因功能變更 要改動,而我這段正在做asp.net mvc +ef+autofac的一個電商網站。索性 就把原來的底層全重新了套用了我現在的架構 EF6.0+autofac+三層架構,上層的asp.net沒有變。改完后發現交班頁面打開巨慢。

   

跟蹤EF生成的sql語句   發現生成的sql 有問題,查找的全表,而全表有近10萬條的數據。

繼續跟蹤數據庫的耗時查詢 發現確實是這條語句占時間

為什么會這樣呢,我在查詢里做條件搜索了,為啥 結果不對呢?

貼出 BaseRepository.cs 的代碼

 1 public class BaseRepository<T> :IDBbase<T>  where T : class
 2     {
 3         //實例化EF框架
 4        protected skdbContext db = new skdbContext();
 5 
 6         //添加
 7         public T AddEntities(T entity)
 8         {
 9             db.Entry<T>(entity).State = EntityState.Added;
10             db.SaveChanges();
11             return entity;
12         }
13 
14         //修改
15         public bool UpdateEntity(T entity)
16         {
17             db.Set<T>().Attach(entity);
18             db.Entry<T>(entity).State = EntityState.Modified;
19             return db.SaveChanges() > 0;
20         }
21 
22         //修改
23         public bool DeleteEntities(T entity)
24         {
25             db.Set<T>().Attach(entity);
26             db.Entry<T>(entity).State = EntityState.Deleted;
27             return db.SaveChanges() > 0;
28         }
29 
30         //查詢
31         public IQueryable<T> LoadEntities(Func<T, bool> wherelambda)
32         {
33             return db.Set<T>().Where<T>(wherelambda).AsQueryable();
34         }
35         //查詢單個
36         public T LoadEntitie(Func<T, bool> wherelambda)
37         {
38             return db.Set<T>().FirstOrDefault<T>(wherelambda);
39         }
40 
41         //分頁
42         public IQueryable<T> LoadPagerEntities<S>(int pageSize, int pageIndex, out int total,
43             Func<T, bool> whereLambda, bool isAsc, Func<T, S> orderByLambda)
44         {
45             var tempData = db.Set<T>().Where<T>(whereLambda);
46 
47             total = tempData.Count();
48 
49             //排序獲取當前頁的數據
50             if (isAsc)
51             {
52                 tempData = tempData.OrderBy<T, S>(orderByLambda).
53                       Skip<T>(pageSize * (pageIndex - 1)).
54                       Take<T>(pageSize).AsQueryable();
55             }
56             else
57             {
58                 tempData = tempData.OrderByDescending<T, S>(orderByLambda).
59                      Skip<T>(pageSize * (pageIndex - 1)).
60                      Take<T>(pageSize).AsQueryable();
61             }
62             return tempData.AsQueryable();
63         }
64     }
View Code

調用代碼 

return jiaobanitem.LoadEntities(t => t.JiaoBanID == jiaobanID && t.GoodsID == GoodsID).FirstOrDefault();

參考 nopCommerce  修改baserepository

  1 public class EFRepository<T> : IRepository<T> where T : class 
  2     {
  3         //實例化EF框架
  4        //protected YaFeiNetContext db = new YaFeiNetContext();
  5        private DbContext _context;
  6        private IDbSet<T> _entities;
  7 
  8        public EFRepository(DbContext context)
  9        {
 10            this._context = context;
 11        }
 12 
 13 
 14         //添加
 15         public virtual T AddEntities(T entity)
 16         {
 17             try
 18             {
 19                 if(entity==null)
 20                     throw new ArgumentNullException("entity");
 21                 
 22                 this.Entities.Add(entity);
 23                 this._context.SaveChanges();
 24                 return entity;
 25             }
 26             catch(DbEntityValidationException dbEx)
 27             {
 28                 var msg = string.Empty;
 29                 foreach(var validationErrors in dbEx.EntityValidationErrors)
 30                     foreach (var validationError in validationErrors.ValidationErrors)
 31                         msg += string.Format("Property:{0} Error:{1}", validationError.PropertyName, validationError.ErrorMessage) + Environment.NewLine ;
 32 
 33                 var fail = new Exception(msg,dbEx);
 34                 throw fail;
 35             }
 36         }
 37 
 38         //修改
 39         public virtual bool UpdateEntities(T entity)
 40         {
 41             try
 42             {
 43                 if (entity == null)
 44                     throw new ArgumentNullException("entity");
 45 
 46 
 47                // this.Entities.Attach(entity);
 48                // _context.Entry<T>(entity).State = EntityState.Modified;
 49                 return this._context.SaveChanges() > 0;
 50             }
 51             catch (DbEntityValidationException dbEx)
 52             {
 53                 var msg = string.Empty;
 54                 foreach (var validationErrors in dbEx.EntityValidationErrors)
 55                     foreach (var validationError in validationErrors.ValidationErrors)
 56                         msg += string.Format("Property:{0} Error:{1}", validationError.PropertyName, validationError.ErrorMessage) + Environment.NewLine;
 57 
 58                 var fail = new Exception(msg, dbEx);
 59                 throw fail;
 60             }
 61 
 62         }
 63 
 64         //修改
 65         public virtual bool DeleteEntities(T entity)
 66         {
 67             try
 68             {
 69                 if (entity == null)
 70                     throw new ArgumentNullException("entity");
 71 
 72                 //db2.Set<T>().Attach(entity);
 73                 //db2.Entry<T>(entity).State = EntityState.Deleted;
 74                 this.Entities.Remove(entity);
 75                 return this._context.SaveChanges() > 0;
 76             }
 77             catch (DbEntityValidationException dbEx)
 78             {
 79                 var msg = string.Empty;
 80                 foreach (var validationErrors in dbEx.EntityValidationErrors)
 81                     foreach (var validationError in validationErrors.ValidationErrors)
 82                         msg += string.Format("Property:{0} Error:{1}", validationError.PropertyName, validationError.ErrorMessage) + Environment.NewLine;
 83 
 84                 var fail = new Exception(msg, dbEx);
 85                 throw fail;
 86             }
 87 
 88 
 89         }
 90 
 91         //查詢
 92         public virtual IQueryable<T> LoadEntities(Func<T, bool> wherelambda)
 93         {
 94             return this.Entities.Where<T>(wherelambda).AsQueryable();
 95         }
 96         //查詢單個
 97         public virtual T LoadEntitie(Func<T, bool> wherelambda)
 98         {
 99             return this.Table.Where(wherelambda).FirstOrDefault();
100         }
101        /// <summary>
102        /// 根據主鍵查找
103        /// </summary>
104        /// <param name="id"></param>
105        /// <returns></returns>
106         public virtual T GetById(object id)
107         {
108             return this.Entities.Find(id);
109         }
110 
111 
112 
113 
114         //分頁
115         public virtual IQueryable<T> LoadPagerEntities<S>(int pageSize, int pageIndex, out int total,
116             Func<T, bool> whereLambda, bool isAsc, Func<T, S> orderByLambda)
117         {
118 
119             var tempData = this.Entities.Where<T>(whereLambda);
120 
121                 total = tempData.Count();
122 
123                 //排序獲取當前頁的數據
124                 if (isAsc)
125                 {
126                     tempData = tempData.OrderBy<T, S>(orderByLambda).
127                           Skip<T>(pageSize * (pageIndex - 1)).
128                           Take<T>(pageSize).AsQueryable();
129                 }
130                 else
131                 {
132                     tempData = tempData.OrderByDescending<T, S>(orderByLambda).
133                          Skip<T>(pageSize * (pageIndex - 1)).
134                          Take<T>(pageSize).AsQueryable();
135                 }
136                 return tempData.AsQueryable();
137             
138 
139         
140         }
141 
142         protected virtual IDbSet<T> Entities
143         {
144             get
145             {
146                 if (_entities == null)
147                     _entities = _context.Set<T>();
148                 return _entities;
149             }
150         }
151 
152 
153         public virtual IQueryable<T> Table
154         {
155             get { return this.Entities; }
156         }
157 
158 
159     }
View Code

同時修改調用代碼 為

return jiaobanitem.Table.Where(t=>t.JiaoBanID ==jiaobanID && t.GoodsID ==GoodsID).FirstOrDefault();

問題解決 頁面響應不到100ms   同時調試中 生成的sql語句已經有 查詢條件了

問題出在  

//查詢
public IQueryable<T> LoadEntities(Func<T, bool> wherelambda)
{
  return db.Set<T>().Where<T>(wherelambda).AsQueryable();
}

為了驗證,我在前台直接調用 

return this.context.Set<tb_e_jiaoBanItem>().Where(t => t.JiaoBanID == jiaobanID && t.GoodsID == GoodsID).AsQueryable().FirstOrDefault();

頁面響應也是 100ms左右,性能沒問題。直接調用 dbcontext的set<>方法 沒問題。但跨了幾層傳遞后 就有問題。並沒有生成我想要的查詢語句。

 

這個問題原來別人也碰到過  http://www.cnblogs.com/yjmyzz/archive/2008/09/06/1285564.html

如果傳入Where的參數為Expression,則L2S會自動幫忙處理Expression的拼接;而如果傳入的是Func,而L2S無法拼接Expression與Func,所以只好先把數據全部取出來,然后再應用Func來進行數據過濾。

代碼應該修改為:

public virtual IEnumerable<T> LoadEntities(System.Linq.Expressions.Expression<Func<T,bool>> wherelambda)
{
return this.Table.Where<T>(wherelambda);
}

 


免責聲明!

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



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