Вопрос

Как вы лениво загружаете вложенные списки без фактического выполнения запроса?Используя очень простой пример, скажем, у меня есть:

class CityBlock {
     IList<Building> BuildingsOnBlock;
     Person BlockOwner;
}

class Building {
     IList<Floor> FloorsInBuilding;
}

class Floor {
     IList<Cubicle> EmployeeCubicles;
}

Class Cubicle {
     System.Guid CubicleID;
     Person CubicleOccupant;
}

И затем в моем слое репозитория у меня есть следующий метод:

GetCityBlocks()

И затем на уровне сервиса у меня будет GetCityBlocksByOwner , где я использую метод расширения, чтобы получить городские кварталы, принадлежащие определенному человеку, скажем, нам просто нужны блоки Guido:

GetCityBlocks().ForOwner("Guido")

Если мы сделаем .ToList() в репозитории, он будет выполнять запросы - это будет нелепо, поскольку мы не знаем, чьи блоки мы получаем на этом уровне.Итак, вопрос в том, как нам сделать это эффективно?

Давайте предположим, что есть 50000 владельцев блоков и около 1000000 городских кварталов, загрузить их все - не вариант.Использование IQueryables не будет работать из-за вложенности (без экстремального взлома, по крайней мере, насколько мне известно).Кроме того, если я попытаюсь использовать что-то вроде LazyList Роба Конери, то у нас, по сути, произойдет утечка из нашего DAL в наши доменные модели, что может быть очень, очень плохо в будущем.

Итак, как мне сделать это правильно?

  • Это вопрос определения правильного контекста?Если да, то сделали бы мы это на уровне хранилища или На уровне сервиса?
  • Должен ли я наполовину объединить уровень сервиса и уровень моего хранилища, чтобы получить очень специфические методы обслуживания?
  • Или я что-то совсем упускаю?(все еще относительно новый для Linq2SQL вещь, которая постепенно прекращается в любом случае, так что ...)

Редактировать: В шаблоне репозитория мы в настоящее время сопоставляем объекты нашего домена, так что это будет выглядеть примерно так:

public IQueryable<CityBlock> GetCityBlocks(){
    var results = from o in db.city_blocks
                  let buildings = GetBuildingsOnBlock(o.block_id)
                  select new CityBlock {
                      BuildingsOnBlock = buildings,
                      BlockOwner = o.block_owner
                  };
    return results;
}

Чтобы это сработало, мы должны были бы сделать так, чтобы здания получили a .ToList() , если только мы не сделаем это фактическое поле в объекте CityBlock IQueryable - что кажется неправильным, потому что кажется, что слишком много полномочий будет предоставлено любому, кто обращается к CityBlock.Поле BuildingsOnBlock.Является ли это сопоставление с объектами нашего домена чем-то, что мы, возможно, должны сделать на уровне сервиса?

Это было полезно?

Решение

Вы делаете это, возвращая IQueryables вместо ILists .

ToList() вызывает немедленное выполнение запросов, поскольку должно быть выполнено преобразование из IQueryable в IList.

Пока вы возвращаете IQueryables, отложенная загрузка должна откладывать выполнение до тех пор, пока данные действительно не понадобятся, т. Е.когда вызывается ToList().

На данный момент я не могу найти ссылку, но, насколько я понимаю, если вы сделаете это таким образом, linq to sql получит возможность оптимизировать SQL, который он отправляет на сервер.Другими словами, в конечном итоге он прочитает эти записи:

GetCityBlocks().ForOwner("Guido")

вместо этих записей:

GetCityBlocks()

Другие советы

Вы могли бы попробовать другой подход к отображению объектов вашего домена, чтобы заставить его работать.Проблема в том, что независимо от того, что вы делаете (если только вы не измените свои списки на IQueryables в объектах вашего домена), вы в конечном итоге будете использовать ToList() во время сопоставления.

Другой способ - позволить Linq2SQL выполнять сопоставление с вашими POCOs, создавая пользовательский datacontext и не используя конструктор для сопоставления :), таким образом, вы сохраняете свою модель домена чистой и позволяете Linq2SQL заполнять зависимости в нужное время.Обратите внимание, что переход на этот маршрут сопряжен со своими собственными проблемами, но это можно сделать.

Вот ссылка, которая поможет вам начать работу по этому маршруту

Достижение POCO s в Linq to SQL

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top