Как фильтровать по полям из свойств навигации в Entity Framework?

У меня есть такие классы, как:

public class ProductInCategory
{
    public Guid Guid { get; set; }
    public long ProductID { get; set; }
    public long ProductCategoryID { get; set; }

    public virtual Product Product { get; set; }
    public virtual ProductCategory ProductCategory { get; set; }
}

public class Product
{
    public virtual ICollection<ProductInCategory> ProductsInCategories { get; set; }

    // and other fields and navigation properties not important for this example
}

И теперь я хочу выполнить запрос, который получает все продукты, используя Entity Framework с быстрой загрузкой с определенными ProductCategoryID:

using (var db = new EntityDataModel())
{
    var node = db.Tree.FirstOrDefault(x => x.Guid == editedNode);
    List<long> descentantIds = db.Tree
                              .Where(x => x.AncestorID == node.AncestorID)
                              .Select(x => x.DescendantID).ToList();

    List<Product> products = db.Products
        .Include("Details")
        .Include("Prices")
        .Include("Prices.Currency")
        .Include("Prices.Seller")
        .Include("Translations")
        .Include("Translations.Language")
        .Include("ProductsInCategories")
        .Where(x => ... )) // how to filter by ProductsInCategories.ProductCategoryID (which in my case is descentantIds) ? 
        .ToList();
}

Я думаю, что мне нужно ввести в предложении Where что-то похожее на .Where(x => descentantIds.Contains(x.ProductsInCategories.ProductCategoryID)), но это не сработает.

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

Спасибо за любой совет!


person Rafal Cypcer    schedule 29.01.2016    source источник
comment
что именно ты хочешь? что descentantIds содержит ЛЮБЫЕ идентификаторы в ProductsInCategories? все? наоборот?   -  person DevilSuichiro    schedule 29.01.2016
comment
Я хочу получить эквивалент SQL WHERE ProductsInCategories.ProductCategoryID IN (1, 2, 3 .. n) , но не понимаю, как получить значение лямбда-выражения ProductCategoryID в моем навигационном свойстве ProductsInCategories. В моем случае оператор Where равен IQueryable<Product>   -  person Rafal Cypcer    schedule 30.01.2016
comment
ProductionCategories — это ICollection of Products, какой ProductCategoryID вам нужен?   -  person DevilSuichiro    schedule 30.01.2016


Ответы (2)


Попробуй это

 .SelectMany(x => x.ProductsInCategories.Where(c => descentantIds.Contains(c.ProductCategoryID))).Select(c => c.Product).Distinct()
person mariovalens    schedule 30.01.2016

Хотя @mariovalens дал рабочее решение, которое решило мою проблему, я нашел другое. Я приклеиваю оба. Это может быть полезно для других ;)

Обратите внимание, что для правильной быстрой загрузки вставьте методы .Include() после методов фильтрации, таких как SelectMany(), Select(), Where() и т. д. Ввод .Include() до того, как эти методы вернут нулевые значения в свойствах навигации.

using (var db = new EntityDataModel())
{
    var node = db.Tree.FirstOrDefault(x => x.Guid == editedNode);
    List<long> descentantIds = db.Tree
               .Where(x => x.AncestorID == node.AncestorID)
               .Select(x => x.DescendantID)
               .ToList();

    List<Product> method1 = db.Products
        .SelectMany(x => x.ProductsInCategories.Where(c => descentantIds.Contains(c.ProductCategoryID))).Select(c => c.Product).Distinct()
        .Include(c => c.Assets.Select(c1 => c1.Translations.Select(c2 => c2.Language)))
        .Include(c => c.Tags.Select(c1 => c1.Translations.Select(c2 => c2.Language)))
        .Include(c => c.Details)
        .Include(c => c.Prices.Select(c1 => c1.Currency))
        .Include(c => c.Prices.Select(c1 => c1.Seller))
        .Include(c => c.Translations.Select(c1 => c1.Language))
        .Include(c => c.ProductsInCategories)
        .ToList();

    var method2 = (from product in db.Products
                 join productsInCategories in db.ProductsInCategories
                 on product.ID equals productsInCategories.ProductID
                 join productsCategories in db.ProductsCategories
                 on productsInCategories.ProductCategoryID equals productsCategories.ID
                 where descentantIds.Contains(productsInCategories.ProductCategoryID)
                 select product)
                 .Include(c => c.Assets.Select(c1 => c1.Translations.Select(c2 => c2.Language)))
                 .Include(c => c.Tags.Select(c1 => c1.Translations.Select(c2 => c2.Language)))
                 .Include(c => c.Details)
                 .Include(c => c.Prices.Select(c1 => c1.Currency))
                 .Include(c => c.Prices.Select(c1 => c1.Seller))
                 .Include(c => c.Translations.Select(c1 => c1.Language))
                 .Include(c => c.ProductsInCategories);

    var result = method2.ToList<Product>();
}
person Rafal Cypcer    schedule 30.01.2016