为什么硬编码函数表达式会使查询加速四分钟?

时间:2010-11-17 17:00:18

标签: linq entity-framework objectset

我使用Dane Morgridge's repository code作为我的存储库类的父级。在父类 - EFRepository中 - 有一个方法调用传递Func方法的ObjectSet的Where子句。在调用此代码然后将其分配给我的网格后,该过程需要4分钟。但是,如果我硬编码对ObjectSet的调用,那么它只需要三秒钟。有什么想法吗?似乎编译器在某种程度上弄乱了它。

private void button1_Click(object sender, RoutedEventArgs e)
    {                        
        IQueryable<PRODDATA> testP = test.Repository.Find(w => w.PCUST == 49 && w.PDTTK == 20101030); 

        DateTime firstDate = System.DateTime.Now;
//This is where it takes the most time when passing in the expression above. When the espression is hardcoded (see below) it speeds it up considerably.
        radGridView1.ItemsSource = testP;
        DateTime secondDate = System.DateTime.Now;                                   

    }

public class EFRepository<T> : IRepository<T> where T : PRODDATA
{
    public IUnitOfWork UnitOfWork { get; set; }
    private IObjectSet<T> _objectset;
    private IObjectSet<T> ObjectSet
    {
        get
        {
            if (_objectset == null)
            {
                _objectset = UnitOfWork.Context.CreateObjectSet<T>();
            }
            return _objectset;
        }
    }

    public virtual IQueryable<T> All()
    {
        return ObjectSet.AsQueryable();
    }

    public IQueryable<T> Find(Func<T, bool> expression)
    {
//Hardcoding this only takes 2 seconds.
        //return ObjectSet.Where(w => w.PCUST == 49 && w.PDTTK == 20101030).AsQueryable(); 

//passing expression takes 4 minutes.
        return ObjectSet.Where(expression).AsQueryable(); 
    }

    public void Add(T entity)
    {
        ObjectSet.AddObject(entity);
    }

    public void Delete(T entity)
    {
        ObjectSet.DeleteObject(entity);
    }

    public void Save()
    {
        UnitOfWork.Save();
    }
}

1 个答案:

答案 0 :(得分:3)

因为Find需要Func<T,bool>而不是Expression<Func<T,bool>>。据推测,此查询正在发送到数据库引擎,因为它在IQueryable<T>上运行。但是,如果表达式作为委托而不是真正的表达式传递,则LINQ-to-whatever-DB层无法检查表达式并将其转换为SQL。这导致整个数据集从数据库服务器发送到C#代码,其中“where”表达式随后应用于CLR而不是DB中。

更改Find的签名
public IQueryable<T> Find(Func<T, bool> expression)

public IQueryable<T> Find(Expression<Func<T, bool>> expression)

然后看看它是如何表现的。