Запрос дочерних коллекций Entity в Entity Framework 4.1

У меня есть набор сущностей, которые я запросил из IDbSet в моем DbContext. Теперь я хочу перебрать каждую сущность и запросить их дочерние коллекции, которые определены в сущности как ICollection. Правильно ли вызывать AsQueryable () в дочерних коллекциях и запускать на них мой запрос linq? Если да, будут ли мои запросы быть linq-to-objects или объект коллекции, заполненный EF, реализует IQueryable, который идет в базу данных?

Спасибо за понимание по этому поводу.


person remy97    schedule 08.05.2011    source источник


Ответы (1)


Все зависит от того, как определены ваши объекты и включена ли ленивая загрузка. Ваш запрос к IDbSet будет linq-to-entity. Если включена отложенная загрузка, доступ к каждому свойству навигации загруженного объекта вызовет запрос к базе данных, который загрузит все связанные объекты. AsQueryable здесь не действует, вы по-прежнему будете выполнять запрос linq-to-objects для всех загруженных данных. В таком сценарии действительно лучше использовать активную загрузку и загружать связанные объекты вместе с основным объектом:

var query = context.YourEntitySet.Include(e => e.YourNavProperty);

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

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

context.Entry(yourLoadedMainEntity)
       .Collection(e => e.YourNavProperty)
       .Query()
       .Where(...)
       .Load();

Это способ заставить EF загружать только подмножество связанных сущностей с помощью linq-to-entity. Вам все равно нужно выполнить это для каждой загруженной основной сущности. Так много запросов выполняется очень медленно. Это все еще проблема N + 1.

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

var query = context.YourEntitySet;
var relatedQuery = from e in context.YourRelatedEntitySet
                   join m in context.YourEntitySet on e.MainId equals m.Id
                   where ...
                   select e;

После выполнения обоих запросов Entity framework должна гарантировать, что свойства навигации правильно заполнены связанными сущностями, но это работает только тогда, когда ленивая загрузка отключена, но сущности отслеживаются по контексту (ну, я никогда не пробовал это с DbContext API, но он работал с ObjectContext API) .

person Ladislav Mrnka    schedule 08.05.2011
comment
Отличное объяснение. Вот мой код: var users = db.Users.Where(u => usernames.Contains(u.UserName)).Include(u => u.Roles).ToList(); var roles = db.Roles.Where(r => roleNames.Contains(r.RoleName)).ToList(); foreach (var user in users) foreach (var role in roles) { var isInRole = user.Roles.AsQueryable().Where(r => r.Id == role.Id) .Count() == 1; if (!isInRole) user.Roles.Add(role); } db.SaveChanges(); Я реализую AddUsersToRoles(string[] usernames, string[] roleNames) в RoleProvider - person remy97; 08.05.2011
comment
Да, хороший ответ. Статья MSDN о том, как загрузить или частично загрузить объекты, связанные с условиями (за исключением того, что одна функция доступна только в EF 5.x): msdn.microsoft.com/en-us/library/gg715120 (v = vs.103) .aspx - person Eugene Y.; 09.03.2012
comment
Есть ли способ запросить дочернюю коллекцию объекта, изменив свойство POCO, а не изменив запрос LINQ (как вы это сделали во втором примере)? Другими словами, заставить свойство работать как EntityCollection ‹›? - person Josh Mouch; 27.09.2012
comment
Я не уверен, что этот ответ по-прежнему работает с Entity Framework 6. Я провел тест с простой сущностью, которая. Загрузите ее коллекцию, и она работает, но когда я использую метод Query (), за которым следует Load, из базы данных ничего не загружается. - person Patrick Desjardins; 25.05.2014