LINQ выполняет несколько запросов вместо одного «присоединенного» запроса - PullRequest
3 голосов
/ 12 апреля 2011

Я ни в коем случае не опытный пользователь LINQ, но могу нащупать свой путь на базовом уровне. У меня есть вопрос относительно того, как LINQ формулирует свой запрос "стратегия". Я постараюсь объяснить это как можно лучше и напишу очень глупый пример по памяти.

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

PersonView

PersonViewId | Surname | GivenName | OtherViewId
------------------------------------------------

OtherView View

OtherViewId | PersonViewId | Name
---------------------------------

После установки первичных ключей для представления (PersonView.PersonViewId / OtherView.OtherViewId) и установки в соответствующих полях необнуляемых значений, я создаю связь между PersonView.PersonViewId (Parent) и OtherView.PersonViewId (Child). Я установил его как «один к одному» и написал некоторый код для его использования:

StringBuilder s = new StringBuilder();
foreach(PersonView p in dc.PersonViews)
{
    s.AppendLine(p.OtherViews.Name + "<br />");
}

Заметив крайне низкую производительность, я профилировал базу данных и заметил, что она выполняет запрос для каждого из PersonView в выражении foreach.

В этот момент я переписал запрос и заменил ассоциацию в DBML на JOIN в запросе LINQ, профилировал базу данных и запросил базу данных, как и ожидалось, только один раз.

Я думаю, что это как-то связано с запросом к БД, но я не уверен, где его отладить. Может ли кто-нибудь указать мне правильное направление, чтобы помочь мне повысить производительность использования ассоциаций, или я застрял, используя JOIN для достижения того, что мне нужно?

Спасибо:)

Ответы [ 3 ]

4 голосов
/ 12 апреля 2011

Это вызвано отложенной загрузкой - вы можете обойти это, применив LoadWith() (эквивалент EF Include() для Linq to SQL) и затем выполнив запрос:

var dlo = new DataLoadOptions();
dlo.LoadWith<PersonView>(p => p.OtherViews);
dc.LoadOptions = dlo;
//your query here
1 голос
/ 12 апреля 2011

Причина, по которой вы видите это, заключается в том, что Linq использует отложенную загрузку для этих отношений. Другими словами, Linq не будет загружать ассоциацию, пока вы на самом деле не попытаетесь ее использовать.

Это может повысить производительность, потому что, если вам не всегда нужна связь, вы не выполняете ненужное JOIN и не получаете данные, которые вам не нужны.

Это может снизить производительность, хотя, если вы уверены, что вам нужны данные, и он продолжает делать запросы.

Вы можете обойти это, сохранив связь, как это было, но используя DataLoadOptions. Например:

var dc = new DataContext();
dc.DeferredLoadingEnabled = false;

DataLoadOptions loadOptions = new DataLoadOptions();
loadOptions.LoadWith<PersonView>(o => o.OtherView);

dc.LoadOptions = loadoptions;

Теперь, каждый раз, когда вы запрашиваете PersonView, он автоматически загружает отношение OtherView.

Хорошая вещь в этом подходе - вы можете включать и выключать его, когда вам это нужно.

1 голос
/ 12 апреля 2011

Это ошибка отложенной загрузки (иначе называемая отложенной загрузкой) LINQ-2-SQL по ошибке, когда вы делаете p.OtherViews.Name, она выполняет запрос к вашей таблице OtherViews.

Есть несколько способов справиться с этим, один из них - отключить отложенную загрузку:

dc.DeferredLoadingEnabled = false;

Другой способ - составить проекцию всего, что вы хотите в своих результатах, и использовать проекцию:

var people = from p in dc.PersonViews
             select new {
                 Person = p,
                 Name = p.OtherViews.Name
             };

А еще есть предложение BrokenGlass, о котором я до сих пор не знал: -)

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