[英]Entity Framework - query execution performance issue
I'm working in a project ASP.NET MVC3 with Entity Framework on SQL Server with performance issues. 我正在使用SQL Server上的Entity Framework的ASP.NET MVC3项目中处理性能问题。
Every time I load data from a view/table using EF and Linq. 每次我使用EF和Linq从视图/表中加载数据。 I can see by SQL Server Profiler that all the table/view content is retrieved because the where condition doesen't appear in profiler.
我可以通过SQL Server Profiler看到所有表/视图内容都被检索,因为where条件不会出现在探查器中。 Only later is filtered by LINQ i think.
我认为只有在LINQ过滤后才会过滤。
Is it correct? 这是正确的吗? How to load only data I need at first on SQL Server?
如何在SQL Server上首先只加载我需要的数据?
This is my example code: 这是我的示例代码:
var query = unitWork.City.GetFirstorDefault(item => item.City == cityCode);
Following an extraction of our datalayer with a data call example. 在使用数据调用示例提取数据层之后。 Thanks for yours replies.
谢谢你的回复。
public class UnitOfWork : IUnitOfWork, IDisposable
{
#region CONSTRUCTOR
public UnitOfWork()
{
_context = new MyApplicationEntities(); //DataContext
_context.ContextOptions.LazyLoadingEnabled = true;
_context.ContextOptions.UseLegacyPreserveChangesBehavior = false;
}
#endregion
// DESC_RECHARGEABLE is a table in DB
public IGenericRepository<DESC_RECHARGEABLE> RepRechargeable
{
get{return _repRechargeable ?? (_repRechargeable = new GenericRepository<DESC_RECHARGEABLE>(_context));}
}
}
public interface IGenericRepository<T> : ICollection<T>
where T : class
{
IEnumerable<T> Query(Func<T, bool> predicate);
void Update(T entity);
T GetFirstorDefault(Func<T, bool> predicate);
IEnumerable<T> GetAll();
T GetByKey(Func<T, bool> predicate);
bool Remove(T entity);
void Add(T entity);
ObjectSet<T> GetQuery();
}
public class GenericRepository<T> : IGenericRepository<T>
where T : class
{
private MyApplicationEntities Currentcontext;
public ObjectSet<T> entitySet;
private List<GenericRepository<T>> _list = null;
private string entityName;
public GenericRepository( MyApplicationEntities context)
{
if (context == null)
throw new ArgumentNullException("context");
this.Currentcontext = context;
this.entitySet = context.CreateObjectSet<T>();
this.entityName = entitySet.Name;
}
#region READ
public IEnumerable<T> Query(Func<T, bool> predicate)
{
return this.entitySet.Where(predicate);
}
public T GetFirstorDefault(Func<T, bool> predicate)
{
return this.Query(predicate).FirstOrDefault();
}
public IEnumerable<T> GetAll()
{
return this.entitySet.AsEnumerable();
}
public T GetByKey(Func<T, bool> predicate)
{
return this.Query(predicate).FirstOrDefault();
}
#endregion
}
//Here a client call example,load all DESC_RECHARGEABLE rows for a condition //这里是客户端调用示例,为条件加载所有DESC_RECHARGEABLE行
var tempList = _unitofWork.RepRechargeable.Query(item => item.COMPANY_CODE == companyCode
&& item.DIVISION_CODE == divisionCode && !string.IsNullOrEmpty(item.PROPERTY));
Ok, based on my comment in the OP, I'm going to stick my neck out here. 好的,根据我对OP的评论,我将在这里坚持下去。
The use of Func<T, bool> predicate
is most likely the root ouf your issue. 使用
Func<T, bool> predicate
很可能是你问题的根源。 When you use Func<>
, your code is excecuted in local memory, against the target structure (in your case, the query
variable). 当您使用
Func<>
,您的代码在本地内存中与目标结构(在您的情况下为query
变量)相同。
By subtley changing the method signatures to use Expression<Func<T, bool>> predicate
, you'll mitigate this issue and will allow for deferred excecution (ie processing on sql server etc). 通过微妙地更改方法签名以使用
Expression<Func<T, bool>> predicate
,您将缓解此问题并允许延迟执行(即在SQL服务器上处理等)。
This is because ( Expression<Func<>>
) creates an expression tree ahead of making the query, and sends this (IQueryable) to the server. 这是因为(
Expression<Func<>>
)在进行查询之前创建表达式树,并将此(IQueryable)发送到服务器。 This then returns the filtered list. 然后返回已过滤的列表。 By contrast, when using
Func<>
, the entire object graph is requested and is post processed in local memory. 相反,当使用
Func<>
,请求整个对象图并在本地内存中进行后处理。
I'm no expert on the mechanics of this, but this should help you figure a solution. 我不是这方面的技术专家,但这应该可以帮助你找到解决方案。
A quick comparison reveals: 快速比较显示:
Func<T>;
Func<T>;
Expression<Func<T>>;
Expression<Func<T>>;
This means that you will only get the deferred IQueryable
by using the Expression<Func<T>>
. 这意味着您只能通过使用
Expression<Func<T>>
获得延迟的IQueryable
。 To round off, here's what your problematic method would now look like: 四舍五入,这就是你现在有问题的方法:
interface: 接口:
T GetFirstorDefault(Expression<Func<T, bool>> predicate);
implementation: 执行:
public T GetFirstorDefault(Expression<Func<T, bool>> predicate)
{
return this.Query(predicate).FirstOrDefault();
}
Obviously, all other methods would follow this change, should it prove successful. 显然,如果证明成功,所有其他方法都将遵循这一变化。
Let me know how this pans out for you. 让我知道这对你来说是怎样的。
[edit] - added a little link (no pun intended), to give a broad outline of the differences between the two: [编辑] - 添加了一个小链接(没有双关语意),概括了两者之间的差异:
Most likely your unitOfWork.City
or .GetFirstOrDefault
method implementation is enumerating the DbSet<T>
prior to applying the filter. 很可能您的
unitOfWork.City
或.GetFirstOrDefault
方法实现在应用过滤器之前枚举DbSet<T>
。 If you show more code, we could pinpoint where this is happening. 如果您显示更多代码,我们可以确定这发生的位置。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.