Условная нетерпеливая загрузка?

Я хочу загрузить сущность и ее детей условно (я хочу загружать детей только тогда, когда child.IsActive == true). Как мне выполнить следующее?

var parent = 
    from p in db.tblParents.Include("tblChildren") <-- where tblChildren.IsActive == true
    where p.PrimaryKey == 1
    select p;

ПРИМЕЧАНИЕ. Я не хочу возвращать анонимный тип.

Благодарю.

3 ответа

Решение

Один из способов сделать это:

var parent = from p in db.tblParents where p.PrimaryKey == 1
             select new {
                 Parent = p,
                 Children = p.tblChildren.Where(c => c.IsActive == true)
             }.ToList();


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

var parent = (from p in db.tblParents where p.PrimaryKey == 1).Single();
var childrens = ctx.Contacts.Where(c => c.ParentID == 1 && c.IsActive == true);
foreach (var child in childrens) {
   parent.tblChildren.Add(child);
}

В Entity Framework 6 вводится перехват http://entityframework.codeplex.com/wikipage?title=Interception который можно использовать для настройки SQL для фильтрации дочерних элементов.

Перед выполнением запроса добавьте перехватчик и удалите его, если он не актуален:

var interceptor = new ActiveTagsInterceptor();
DbInterception.Add(interceptor);

documents = context.Documents
                .AsQueryable()
                .Include(d => d.Tags)

DbInterception.Remove(interceptor);

Образец перехватчика, который добавляет "[Active] = 1 А" при загрузке тегов:

public class ActiveTagsInterceptor : IDbCommandInterceptor
{
    public void NonQueryExecuting(DbCommand command, DbCommandInterceptionContext<int> interceptionContext)
    {
    }

    public void NonQueryExecuted(DbCommand command, DbCommandInterceptionContext<int> interceptionContext)
    {
    }

    public void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
    {
        // [Tag] AS [Extent6] ON   => [Tag] AS [Extent6] ON [Extent6].[Active] = 1 And 
        const string pattern = "\\[Tag\\]\\sAS\\s\\[([\\w]+)\\]\\sON";
        const string replacement = "$& [$1].[Active] = 1 And ";
        command.CommandText = Regex.Replace(command.CommandText, pattern, replacement);
    }

    public void ReaderExecuted(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
    {
    }

    public void ScalarExecuting(DbCommand command, DbCommandInterceptionContext<object> interceptionContext)
    {
    }

    public void ScalarExecuted(DbCommand command, DbCommandInterceptionContext<object> interceptionContext)
    {
    }
}

Чтобы иметь возможность применить фильтр, лучше использовать явную загрузку вместе с Query() вместо быстрой загрузки:

var parent = db.tblParents.Find(1);
db.Entry(parent).Collection(p => p.tblChildren).Query().
    Where(child => child.IsActive).Load();

Метод Query обеспечивает доступ к базовому запросу, который Entity Framework будет использовать при загрузке связанных сущностей. Также вам нужно отключить отложенную загрузку для свойства навигации (удалить ключевое слово Virtual), иначе коллекция автоматически загружается отложенной загрузкой, которая игнорирует ваш фильтр.

Другие вопросы по тегам