Замедляет ли использование лямбда-выражения, переданного в метод, запрос Entity Framework? - PullRequest
9 голосов
/ 31 января 2011

У меня есть метод:

public static void GetObjects()
{
    using(MyContext context = new MyContext())
    {
         var objects = context.Bars.Where(b => b.Prop1 != null)
                       .Select(b => new MyObject{Prop = b.Prop1, Name = b.Name})
                       .ToList();
         foreach(var object in objects)
         {
             // do something with the object
         }
    }
}

Я реорганизовал метод, чтобы сделать его более общим, чтобы я мог передать Func, чтобы я мог указать оператор where и какое свойство из таблицы Bars будет присвоено MyObject.Prop следующим образом:

public static void GetObjectsV2(Func<Bar, bool> whereFunc, Func<Bar, string> selectPropFunc)
{
    using(MyContext context = new MyContext())
    {
         var objects = context.Bars.Where(whereFunc)
                       .Select(b => new MyObject{Prop = selectPropFunc(b), Name = b.Name})
                       .ToList();
         foreach(var object in objects)
         {
             // do something with the object
         }
    }
}

GetObjectsV2, кажется, работает намного медленнее, чем GetObjects. Существуют ли какие-либо причины, которые могут повлиять на производительность, и если да, то есть ли способы обойти это, сохраняя при этом гибкость функции?

Ответы [ 2 ]

16 голосов
/ 31 января 2011

Причина, по которой он работает медленнее, заключается в том, что вы передаете Func<Bar, bool>, который заставляет контекст извлечь все столбцы, а затем запустить Func для возвращенного набора результатов. Способ сделать этот пробег лучше - передать Expression<Func<Bar, bool>>

Объединение всего этого приведет к следующему:

public static void GetObjectsV2(Expression<Func<Bar, bool>> whereFunc, Expression<Func<Bar, string>> selectPropFunc)
{
    using(MyContext context = new MyContext())
    {
         var objects = context.Bars.Where(whereFunc)
                       .Select(selectPropFunc)
                       .ToList();
         foreach(var object in objects)
         {
             // do something with the object
         }
    }
}
5 голосов
/ 31 января 2011

Как я обнаружил в своем собственном вопросе , .Where(o => whereFunc(o)) - это не то же самое, что .Where(whereFunc) в Entity Framework.

Первый, .Where(Expression<Func<Bar, bool>>) работает как любой другойВызов linq, просто добавление выражения к дереву выражений.

Во втором случае, .Where(Func<Bar, bool>>), он скомпилирует и оценит вызов linq (который пока что является просто context.Bars) перед применением whereFunc Предикат.


Итак, чтобы ответить на ваш вопрос, второй намного медленнее, потому что он вытягивает всю таблицу Bars в память, прежде чем что-либо делать с ней.Использование .Where(o => whereFunc(o)) вместо этого должно исправить это

(или, как предлагает Марк, изменить тип whereFunc на Expression<Func<Bar, bool>>, к которому Func<Bar, bool> неявно конвертируется)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...