1

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

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, где Я использую метод расширения, чтобы получить городские блоки, принадлежащие конкретным человеком, скажем, мы просто хотим, блоки Гвидо:

GetCityBlocks().ForOwner("Guido") 

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

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

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

  • Вопрос об определении правильного контекста ? Если да, будем ли мы делать в слое репозитория или на уровне сервиса ?
  • Я получу общий уровень обслуживания и уровень моего хранилища, чтобы получить очень специфические методы обслуживания?
  • Или я чего-то не хватает? (Все еще относительно новое для Linq2Sql вещь, которая постепенно сокращается в любом случае, так ...)

Edit: В хранилище шаблон, мы в настоящее время отображение наших объектов предметной области, так это будет выглядеть примерно так:

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; 
} 

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

+0

Вся фаза-аут, что это отвлекающий маневр. Хотя это правда, что он не собирается уделять много внимания с точки зрения улучшений, он уже находится в рамках, поэтому он будет с нами некоторое время. В любом случае, StackOverflow использует Linq для SQL, и я бы сказал, что он работает очень хорошо. –

+0

Что вы возвращаете из своего метода GetCityBlocks()? Поскольку вы используете фильтры расширений, я думаю, вы уже возвращаете IQueryable правильно? иначе вы действительно должны использовать ответ Роберта для этого. Обратите внимание, что публикация IQueryable из вашего репозитория означает только предоставление Linq не Linq2Sql – Jaime

ответ

1

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

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

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

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

GetCityBlocks().ForOwner("Guido") 

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

GetCityBlocks() 
+0

Но наличие IQueryables в модели домена кажется проблемой из-за того, что вы делаете это JUST для выполнения DAL, а не потому, что это что-то, что является частью этого домена модель. IQueryable не обязательно то, что вам нужно для запроса этих полей/свойств/объектов класса в этом объекте. Или я все еще неправильно рассматриваю эту проблему? – MunkiPhD

+0

Существует точка зрения, что если вы возвращаете IQueryables на уровень обслуживания, тогда уровень сервиса не имеет «четко определенного интерфейса» (вы даете ему слишком много возможностей для манипулирования запросом). Так что есть компромисс. Это сделает ваш репозиторий намного проще (потому что вам не нужны методы для каждого возможного запроса), и он действительно имеет силу делать то, что вы хотите. Я не юрист с шаблонами, поэтому я не скажу вам, что вы не можете сделать это таким образом, но кто-то другой. –

+0

Я согласен с вами в том, что немного ослабляет элементы управления, но что, если мы сопоставляем наши собственные объекты в репозитории? Это что-то мы должны делать в другом месте? (см. мое редактирование) – MunkiPhD

0

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

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

Вот ссылка, чтобы вы начали на этом маршруте

Achieving POCO s in Linq to SQL

 Смежные вопросы

  • Нет связанных вопросов^_^