2008-12-03 2 views
9

В настоящее controversial blog post, Hackification понтификатами на то, что, как представляется, ошибка в новом LINQ В рамках Entities:LINQ To Entities и Ленивый Загрузка

Предположим, я ищу для клиента:

var alice = data.Customers.First(c => c.Name == "Alice"); 

Хорошо, что хорошо работает. Теперь давайте посмотрим , если я могу найти одну из своих заказов:

var order = (from o in alice.Orders 
      where o.Item == "Item_Name" 
      select o).FirstOrDefault(); 

LINQ к SQL будет найти дочернюю строку. LINQ-to-Entities будет молча возвращаться ничего.

Теперь давайте предположим, что я перебирать все заказы в базе данных:

foreach(var order in data.Orders) { 
Console.WriteLine("Order: " + order.Item); } 

А теперь повторю свой поиск:

var order = (from o in alice.Orders 
      where o.Item == "Item_Name" 
      select o).FirstOrDefault(); 

Wow! LINQ-to-Entities внезапно говорит мне, что дочерний объект существует, , несмотря на то, что раньше я говорил, что он не сделал!

Моя первая реакция была, что это должно было быть ошибка, но после дальнейшего рассмотрения (и backed up by the ADO.NET Team), я понял, что такое поведение было вызвано Entity Framework не отложенной загрузки Заказы подзапрос, когда Алиса вытягивается из DataContext.

Это потому, что порядок является LINQ-To-объект запроса:

var order = (from o in alice.Orders 
     where o.Item == "Item_Name" 
     select o).FirstOrDefault(); 

И не имеет доступа к DataContext в любом случае, в то время как его Еогеасп цикла:

foreach(var order in data.Orders) 

ли доступ к DataContext ,

LINQ-To-SQL фактически создал ленивые загружаемые свойства для ордеров, так что при обращении к нему, выполнив другой запрос, LINQ to Entities предоставит вам возможность вручную получать связанные данные.

Теперь я не большой поклонник ОРМ, и это точно причина. Я обнаружил, что для того, чтобы все данные, которые вы хотите готовить под рукой, они многократно выполняют запросы за вашей спиной, например, что указанный выше запрос linq-to-sql может запускать дополнительный запрос для каждой строки Клиентов для получения заказов ,

Однако EF, не делая этого, по-видимому, нарушает принцип наименьшего удивления. Хотя это технически правильный способ сделать что-то (вы должны запустить второй запрос для получения заказов или получить все из представления), он не ведет себя так, как вы ожидали бы от ORM.

Итак, это хороший дизайн каркаса? Или Microsoft думает об этом для нас?

ответ

1

Я мало знаю об ORM, но, как пользователь LinqToSql и LinqToEntities, я хотел бы надеяться, что при попытке запросить заказы для Алисы он сделает дополнительный запрос для вас, когда вы сделаете запрос linq (в противоположность не запрашивать ничего или не запрашивать все для каждой строки).

кажется естественно ожидать

from o in alice.Orders where o.Item == "Item_Name" select o 

к работе, при условии, что это одна из причин, почему люди используют ОРМ в первом месте (для упрощения доступа к данным).

Чем больше я читал о LinqToEntities, тем больше я думаю, что LinqToSql удовлетворяет большинство разработчиков. Обычно мне просто нужно сопоставление таблиц один-к-одному.

2

Если LINQ-to-Sql и LINQ-to-Entities пришли из двух разных компаний, это будет приемлемой разницей - нет закона о том, что все LINQ-To-Whatevers должны быть реализованы одинаково.

Тем не менее, оба они исходят от Microsoft - и нам не нужно знать глубокое знание своих внутренних команд и процессов разработки, чтобы знать, как использовать две разные вещи, которые на их лице выглядят точно так же.

ORM имеют свое место и действительно заполняют пробел для людей, пытающихся добиться результата, но использование ОРМ должно точно знать, как их ORM выполняет все это - лечение его как непроницаемого черного ящика приведет вас к неприятностям ,

5

Итак, это хороший дизайн каркаса? Или Microsoft думает об этом для нас?

Ну давайте проанализируем это - все мысли, что Microsoft делает, что нам не нужно на самом деле заставлять нас ленивых программистов. Но в целом это делает нас более продуктивными (по большей части). Так они более мышления или они просто мышления для нас?

1

Несмотря на то, что вам не нужно знать о внутренних командах и процессах разработки Microsoft, дело в том, что эти две технологии - это два совершенно разных зверя.

Конструктивное решение для LINQ to SQL было, для простоты, неявно ленивой загрузкой коллекций. Команда ADO.NET Entity Framework не выполнила запросы без запроса пользователя, поэтому они разработали API для явной загрузки для первой версии.

LINQ to SQL был передан команде ADO.NET, и поэтому вы можете увидеть консолидацию API в будущем или LINQ to SQL свернуть в Entity Framework, или вы можете увидеть атрофию LINQ to SQL из пренебрежения и в конечном итоге становятся устаревшими.

12

Jon,

Я также играл с linq для сущностей. У него есть длинный путь, прежде чем он догонит linq к SQL. Мне пришлось использовать linq для сущностей для материала Table for Type Inheritance. Недавно я нашел хорошую статью, которая объясняет всю 1 компанию 2 разных ORM-технологий here.

Однако вы можете сделать отложенную загрузку, таким образом, делая это:

// Lazy Load Orders 
var alice2 = data.Customers.First(c => c.Name == "Alice"); 

// Should Load the Orders 
if (!alice2.Orders.IsLoaded) 
    alice2.Orders.Load(); 

или вы можете просто включить заказы в исходном запросе:

// Include Orders in original query 
var alice = data.Customers.Include("Orders").First(c => c.Name == "Alice"); 

// Should already be loaded 
if (!alice.Orders.IsLoaded) 
    alice.Orders.Load(); 

Надеется, что это помогает.

Dave

+2

Согласен, этот пост в блоге не полностью информирован. Я считаю, что они должны были потратить немного времени на изучение L2E, прежде чем критиковать его так, как будто они решили, что им это не нравится, прежде чем они написали статью, вызвав огромное волнение, потому что они не знали, что им нужно было загрузить() ... – naspinski 2009-01-06 07:07:54

2

Потеряв несколько дней до этой самой проблемы, я сочувствую.

«Ошибка», если таковая существует, заключается в том, что существует разумная тенденция ожидать, что слой абстракции будет изолирован от этих проблем. Переход от LINQ к объектам к слою базы данных вдвойне.

Чтобы переключиться с MS-SQL (используя LingToSQL) на MySQL (используя LinqToEntities), например, можно было бы предположить, что LINQ, по крайней мере, будет таким же, если не только для экономии от стоимости перезаписывать программную логику.

Необходимо, чтобы код помета с помощью .Load() и/или LINQ с .Include() просто потому, что механизм сохранения в капот изменился, кажется немного тревожным, особенно с тихим сбоем. Уровень LINQ должен, по крайней мере, вести себя последовательно.

Ряд структур ORM использует прокси-объект, чтобы динамически загружать ленивый объект прозрачно, а не просто возвращать null, хотя я был бы доволен исключением, не загруженным коллекцией.

Я склоняюсь к тому, чтобы не покупать в своих предлогах преднамеренное для вас; другие рамки ORM позволяют вам комментировать, хотите ли вы, чтобы они были нетерпеливыми или ленивыми по мере необходимости. То же самое можно сделать здесь.