EF 4.0 / Странное поведение метода FirstOrDefault - PullRequest
3 голосов
/ 22 августа 2010

Я занимаюсь разработкой небольшого приложения с использованием EF 4.0 и POCO.

Во время тестирования моего приложения я начал беспокоиться о производительности уровня доступа к данным. Поэтому я запустил SQL Profiler, чтобы увидеть, что при попытке извлечь запись:

ctx.Orders.Include("OrderItems").FirstOrDefault<Order>(c => c.OrderID == id);

EF выдает оператор SQL, который извлекает все записи из таблицы «Заказы» на Сервере и, как таковой, возвращает DAL, когда L2E выбирает один из них, удовлетворяющий критериям, и возвращает его.

Можно ли изменить это поведение.

Спасибо!

Zen

1 Ответ

9 голосов
/ 22 августа 2010

Попробуйте, пожалуйста:

ctx.Orders.Include("OrderItems").Where(c => c.OrderID == id).FirstOrDefault();

Кстати, вам не нужно заглядывать в SQL Profiler, чтобы увидеть сгенерированный SQL, вы можете сделать это прямо в коде, написав:

IQueryable<Order> query = ctx.Orders.Include("OrderItems")
                                    .Where(c => c.OrderID == id);
string sql = ((ObjectQuery<Order>)query).ToTraceString();

EDIT: Вопрос: Что если у нас есть такая функция, как FindOrders , и нам нужно передать предикат этой функции?Ответ: код должен выглядеть так:

public List<Order> FindOrders(Expression<Func<Order, bool>> predicate) { 
    using (DBContext ctx = new DBContext()) { 
        return ctx.Orders.Include("OrderItems").Where(predicate).ToList<Order>(); 
    } 
} 

//Calling the function:
var order = FindOrders(c => c.OrderID == id)[0];

На этот раз, если вы проверите свой SQL Profiler, вы увидите, что в SQL есть предложение where, которое было отправлено на SQL Server. Пояснение: Причина этого «странного поведения» заключается в том, что в основном, когда вы пишете Where (c => c.OrderID == id), компилятор C # преобразует ваше лямбда-выражение в выражение> а НЕ ФУНКЦИИ, Документация MSDN для Queryable. Где также подтверждает это: <pre> public static IQueryable<TSource> Where<TSource>( this IQueryable<TSource> source, Expression<Func<TSource, int, bool>> predicate ) Однако, если вы явно передаете Func> к методу Where, тогда вы в основном вызываете Enumerable.Where: <pre> public static IEnumerable<TSource> Where<TSource>( this IEnumerable<TSource> source, Func<TSource, int, bool> predicate ) И, как мы знаем IEnumerable.Where - это реализация «LINQ to Objects», а НЕ «LINQ to Entities», что означает, что вы достигнете своего IEnumerable.Where, ObjectQuery запускает начальный запрос (ctx.Orders.Include («OrderItems»)) и передает результаты в IEnumerable.Where, чтобы он отфильтровал их для вас на Client Side .С другой стороны, вызов с Queryable.Where (ctx.Orders.Include ("OrderItems"). Где (c => c.OrderID == id) .FirstOrDefault ()) не будет выполнен, пока не достигнет точки, котораямы вызываем функцию FirstOrDefault (), которая означает Queryable.Where затем переводится в собственный SQL вместе с остальной частью запроса и передается на SQL Server, следовательно, вы видите предложение Where в операторе SQL, которое определенно является желаемой средой выполненияповедение.Кстати, не забудьте импортировать это пространство имен в ваш файл класса: <pre> using System.Linq.Expressions;

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