简体   繁体   English

实体框架 - 查询执行性能问题

[英]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: 快速比较显示:

  • the extension methods for IEnumerable operate with Func<T>; IEnumerable的扩展方法用Func<T>;
  • the extension methods for IQueryable operate with Expression<Func<T>>; IQueryable的扩展方法使用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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM