LINQ To Entities и Ленивая Загрузка - PullRequest
9 голосов
/ 04 декабря 2008

В противоречивый блог Сегодня, Hackification понтификатами на то, что, как представляется, ошибка в новом 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-to-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();

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

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

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

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

И не имеет никакого доступа к текстовому тексту данных, пока его цикл foreach:

 foreach( var order in data.Orders )

Доступ к текстовому тексту данных.

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

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

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

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

Ответы [ 6 ]

12 голосов
/ 18 декабря 2008

Джон,

Я также играл с linq для сущностей. Ему предстоит пройти долгий путь, прежде чем он догонит linq to SQL. Мне приходилось использовать linq для сущностей для таблицы наследования типов. Недавно я нашел хорошую статью, в которой объясняется, что целая 1 компания 2 разные технологии ORM здесь .

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

// 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

5 голосов
/ 04 декабря 2008

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

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

2 голосов
/ 26 февраля 2010

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

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

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

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

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

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

2 голосов
/ 04 декабря 2008

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

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

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

1 голос
/ 10 декабря 2008

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

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

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

1 голос
/ 04 декабря 2008

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

Кажется естественным ожидать

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

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

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

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