2017-02-20 25 views
1

Я работаю с схемой DB, где записи не перезаписываются при обновлении. Скорее новая копия записи добавляется и помечена как «текущая».Entity Framework - Нежелательная загрузка фильтра?

Например:

Id | Current | Name | Owner 
1 | false | Foo | Bar 
1 | false | Foo | Bazz 
1 | true | Foo | Buzz 

В моей модели у меня есть Blog юридического лица, которое имеет много Post сек, связанных с ним. Каждый Post имеет много Comment сек, связанные с ним:

public class Blog 
{ 
    public int Id {get; set}; 
    public bool Current {get; set}; 
    public ICollection<Post> Posts {get; set;} 
} 

public class Post 
{ 
    public int Id {get; set}; 
    public bool Current {get; set}; 
    public ICollection<Comment> Comments {get; set;} 
} 

public class Comment 
{ 
    public int Id {get; set}; 
    public bool Current {get; set}; 
} 

Я хотел бы охотно загрузить Blog со всеми его Post с и все их Comment ей так же, как в this example from MSDN:

using (var context = new BloggingContext()) { // Load all blogs, all related posts, and all related comments var blogs1 = context.Blogs .Include(b => b.Posts.Select(p => p.Comments)) .ToList(); }

Однако я хотел бы включить только записи БД, где Current == true. Как это сделать с LINQ-to-EF? В идеальном случае условие входило бы в статью JOINON - это возможно?

+1

Вопрос не очень ясен, а как насчет .Include (b => b.Posts.Select (p => p.Comments.Where (comment => comment.Current))) ?? –

+0

@ a-t Спасибо. То, что не ясно? Ваше предложение не распространяется на блоги и сообщения и дает мне: «В выражении« Включить путь »должно быть указано свойство навигации, определенное в типе. Используйте точечные пути для ссылочных свойств навигации и оператор« Выбор »для свойств навигации для коллекции». – urig

ответ

1

Отказ от ответственности: Я владелец проекта Entity Framework Plus

ЭФ + Query IncludeFilter позволяют легко фильтровать входящие объекты.

using (var context = new BloggingContext()) 
{ 
    // Load all blogs, all related posts, and all related comments 
    var blogs1 = context.Blogs 
        .IncludeFilter(b => b.Posts.Where(x => x.Current)) 
        .IncludeFilter(b => b.Posts.Where(x => x.Current).Select(p => p.Comments.Where(x => x.Current)) 
        .ToList(); 
} 

Примечание: Каждый путь должен быть включен из-за некоторых ограничений библиотеки с навигационными свойствами.

Wiki: EF+ Query Include Filter


Ответ подвопрос

Одна из проблем: SQL, излучаемый очень велико.

SQL генерируется Entity Framework. SQL очень велик из-за того, как они обрабатывают отношение в методе проектирования и включения. Наша библиотека не генерирует этот SQL.

Вы можете изменить большой SQL, сгенерированный с помощью EF+ Query IncludeOptimized, для выполнения нескольких инструкций. Использование нескольких операторов часто повышает производительность.

Пример:

using (var context = new BloggingContext()) 
{ 
    // Load all blogs, all related posts, and all related comments 
    var blogs1 = context.Blogs 
        .IncludeOptimized(b => b.Posts.Where(x => x.Current)) 
        .IncludeOptimized(b => b.Posts.Where(x => x.Current).Select(p => p.Comments.Where(x => x.Current)) 
        .ToList(); 
} 

Примечание: Каждый путь должен быть включен из-за некоторые ограничения библиотеки с навигационными свойствами.

Wiki: EF+ Query IncludeOptimized

+0

Спасибо за этот ответ. Из-за предостережения в моем собственном ответе ниже я решил использовать EF + Include Filter. Полученные результаты будут точно такими же, как ожидалось. Одна проблема: испущенный SQL очень большой. Содержит несколько предложений UNION, когда кажется, что на самом деле нужен только последний ...? (Это та, где все таблицы объединены вместе.) – urig

0

Фильтрация при активной загрузке с .Include() в настоящее время не поддерживается «из коробки» с помощью Entity Framework. Вы можете vote in favor of this feature here и, надеюсь, он сделает разрез в EF7.

Я нашел частичный ответ на мой вопрос в библиотеке с открытым исходным кодом под названием EntityFramework.Include, которая предоставляет некоторые возможности фильтрации во время активной загрузки.

К сожалению, я только был в состоянии использовать его для двух (из трех) уровней моей иерархии примерно так:

using (var context = new BloggingContext()) 
{ 
    // Load all blogs and all related posts that are "Current" 
    var query = context.Blogs 
     .Where(b => b.Current) 
     .Include(b => b.Posts, b => b.Posts.Where(p => p.Current).ToList()); 
    var list = query.ToListWithInclude(); 
} 

Тем не менее, пытаясь выяснить, как пойти на один уровень глубже в Comment с.

+0

Существует также [EntityFramework.Filters] (https://github.com/jbogard/EntityFramework.Filters/), но, к сожалению, его фильтры не применяются к '.Include()'. – urig

1

Найдено решение с использованием "из коробки" Entity Framework на основе this StackOverflow answer.

Ключевое понятием является добавление родительского свойства для каждого объекта, а затем перейти «назад» от самого низкого уровня иерархии до самого верха:

var query = context.Comments 
    .Include("Post.Blog") 
    .Where(comment => 
     comment.Current && 
     comment.Post.Current && 
     comment.Post.Blog.Current) 
    .Select(comment => comment.Post.Blog) 
    .ToList(); 

Одним из важного предостережения, который упоминается в комментарий к этому ответу:

... если существуют родители, у которых нет детей, соответствующих фильтрам, эти родители не будут в результирующем наборе.