EF 6 фильтрует детские коллекции
Я пытаюсь перенести старый проект из Linq2Sql в EF6, и у меня возникла следующая проблема.
Этот проект является многоязычным (т.е. все тексты имеют более одного перевода), и у меня есть следующая структура db:
![Пример таблиц БД]()
Каков наилучший способ получить все объекты ExampleEntity1 со всеми записями LocalizedContent, отфильтрованными текущим идентификатором языка?
Я могу загрузить все объекты ExampleEntity1 со всеми записями LocalizedContent, используя следующий код:
dc.ExampleEntity1.Include(ee => ee.TextEntry.LocalizedContents);
В Linq2Sql я могу фильтровать записи LocalizedContent с помощью loadOptions.AssociateWith
, но я не могу найти решение для EF6.
Я видел похожие старые вопросы (размещенные как 2-3 года назад), и мне просто интересно, есть ли решение для EF6. Это очень важная функция для меня, потому что у меня есть десятки объектов в проекте, и я не хочу создавать пользовательские объекты для каждого запроса выбора.
Я также нашел пакет EntityFramework.DynamicFilters nuget, который может помочь с моей проблемой, но я предпочел бы использовать "родную" функциональность EF6, если это возможно..
Ответы
Ответ 1
Если вы хотите выполнить фильтрацию в запросе в базе данных, тогда (с EF6) вы должны использовать метод Query
Метод Query обеспечивает доступ к базовому запросу, который будет использоваться Entity Framework при загрузке связанных объектов. Затем вы можете использовать LINQ для применения фильтров к запросу перед выполнением его с вызовом метода расширения LINQ, такого как ToList, Load и т.д.
using (var context = new BloggingContext())
{
var blog = context.Blogs.Find(1);
// Load the posts with the 'entity-framework' tag related to a given blog
context.Entry(blog)
.Collection(b => b.Posts)
.Query()
.Where(p => p.Tags.Contains("entity-framework")
.Load();
// Load the posts with the 'entity-framework' tag related to a given blog
// using a string to specify the relationship
context.Entry(blog)
.Collection("Posts")
.Query()
.Where(p => p.Tags.Contains("entity-framework")
.Load();
}
Однако очевидным недостатком является то, что вы должны сделать это для каждой записи, и каждый вызов Load
выполняет запрос к базе данных.
Если это не будет жестким требованием для вас, я бы выбрал только загрузку всех локализаций и просто фильтрацию в памяти для использования выбранного языка. Я уверен, что производительность не будет проблемой.
Ответ 2
Обратите внимание, что в настоящее время невозможно фильтровать связанные загружаются объекты. Include всегда будет включать все связанные сущности.
Ссылка Msdn
var result = dc.ExampleEntity1.Include(ee =>ee.TextEntry.LocalizedContents)
.Select(x=>new
{
//Try anonymous or a projection to your model.
//As this Select is IQuerable Extension it will execute in the data store and only retrieve filtered data.
exampleEntity = x,
localizedContetnt = x.TextEntry.LocalizedContents.Where(g=>g.Id==YourKey),
}).FirstOrDefault();
Вы можете попробовать анонимную проекцию для фильтрации содержимого в включенных сущностях
Команда сообщества Entity работает над этим, вы можете проголосовать здесь
Похожие ответы
Ответ 3
НЕ тестировался И не идеален с точки зрения производительности из-за того, как включить работу... Я бы сделал это вручную, но вот пример того, что вы могли бы сделать.
var result = dc.ExampleEntity1
.Include(x => x.TextEntry)
.Include(x => x.TextEntry.LocalizedContents)
.Include(x => x.TextEntry.LocalizedContents.Local)
.Where(x => x.id == 'ExampleEntity1Key'
&& x.TextEntity.LocalContent.Local.Id == 'Value'
)
.FirstOrDefault();
Это приведет к тому, что объект ExampleEntity1 будет загружен с полной загрузкой навигации.... где Local сопоставляется с идентификатором.
вы могли бы получить Local как..
var listLocalsForExampleEnitity = result.TextEntry.LocalizedContents.Local.ToList();
или просто вызывать их из того места, где они уже находятся в памяти.
Надеюсь, что это поможет