EF5 ObjectContext: как заменить IQueryable <T>.Include(Path) с context.T.Attach()
Я использую Entity Framework 5 с ObjectContext в относительно большой и сложной модели данных.
Я хотел бы работать с большими запросами, генерируемыми при связывании нескольких объектов IQueryable.Include(Path) с объектами, связанными с загрузкой.
Например, я делаю что-то вроде этого:
var queryPe = context.Person.Where(p => p.Id == 110).Include(@"AA");
queryPe = queryPe.Include(@"BB.CC.DD");
queryPe = queryPe.Include(@"EE.FF");
Это можно сделать общим с помощью строкового массива и привязки каждого графика во время выполнения в цикле foreach.
Вместо этого я хотел бы сделать что-то вроде этого:
Person pe = context.Person.Where(p => p.Id == 110).First();
context.LoadProperty(pe, "AA");
pe.BB.Attach(pe.BB.CreateSourceQuery().Include(@"CC.DD"));
pe.EE.Attach(pe.EE.CreateSourceQuery().Include(@"FF"));
Вместо того, чтобы иметь один большой запрос, у нас было бы 4 меньших запроса, попадающих в базу данных.
Конечно, я все еще хочу использовать силу графического пути как строку.
Возможно, я ошибаюсь, но это означает, что я должен использовать relexion для получения свойств навигации по имени и выполнения CreateSourceQuery() на нем, потому что для этого не существует такого метода расширения.
Правильно ли я?
EDIT 1: У меня есть дополнительное ограничение, то есть я использую Self Tracking Entities (STE). Это означает, что Связанные объекты не реализованы как EntityCollection или EntityReference. Поэтому Attach() и CreateSourceQuery() недоступны!
Итак, я застрял в Context.LoadProperty для обработки графов объектов.
Возможно ли это?
EDIT 2: проблема, обнаруженная в EDIT 1, решена благодаря использованию класса DbContext. См. Код ниже:
Person pe = context.Person.Where(p => p.Id == 110).First();
context.LoadProperty(pe, "AA");
DbContext dbc = new DbContext(context, false);
dbc.Entry(pe).Collection(@"BB").Query().Include(@"CC.DD").Load();
dbc.Entry(pe).Reference(@"EE").Query().Include(@"FF").Load();
РЕДАКТИРОВАТЬ 3 02/11/2013. Существует проблема с приведенным выше кодом (EDIT 2). Если последний объект в пути является ссылкой, а не коллекцией, код не прерывается, но он не загружается: - (
РЕДАКТИРОВАТЬ 4: вместо использования рефлексии, прямо сейчас, я генерирую код, просматривая модель данных сущности с помощью шаблона T4.
Ответы
Ответ 1
Иногда хранимые процедуры лучше всего. Напишите хранимую процедуру, которая возвращает несколько наборов результатов, по одному для каждого типа объектов, которые вы хотите с нетерпением загружать. Это очень результативно по сравнению с тем, что вы пытаетесь выполнить, и хранимая процедура будет намного читабельнее, чем этот беспорядок включает в себя и отдельные инструкции загрузки для каждой ссылки/коллекции. И да, EF автоматически подключит связанные объекты.
Здесь ссылка для sprocs с несколькими наборами результатов для EDMX и кода:
http://msdn.microsoft.com/en-us/data/jj691402.aspx
Ответ 2
Попробуйте разделить агрегаты в нескольких контекстах. Каждый ограниченный контекст должен иметь отдельный контекст. Таким образом, вы создаете слабо связанную инфраструктуру сущности.
У Джулии Лерман есть хорошее видео о множественном взгляде на эту концепцию.
Ответ 3
Я бы предпочел использовать хранимые процедуры. Простота обслуживания, работает быстрее и т.д.