I\'m using EF 6 to get products from a database. The product categories are mapped as a navigation property on products, and the data is from a ProductCategory pivot table. The
Try first filtering out the products and only then forming your models (Product_PL and Category_PL):
var filteredProducts = db.Products.Where(p => p.Categories.Any(c => currentCategoryIdAndChildren.Contains(c.ID)))
.Select(p => new Product_PL
{
id = p.ID,
name = p.Name,
description = p.Description,
categories = p.Categories
.Select(c => new Category_PL
{
categoryid = c.ID,
}),
});
I tried many different things and finally found a solution.
I believe the main slowdown happened when EF was translating the Contains() into a SQL query. The most noticeable thing, however, was that it did not appear to cache the query. From what I can gather, this is because the list of category IDs (currentCategoryIdAndChildren) was generated outside of EF, so it assumed it would be different every time.
I was able to speed things up by using the PredicateBuilder in LINQKit. This allowed me to create the logic more explicitly:
var IsInCategory = PredicateBuilder.False<Product_PL>();
foreach (int categoryID in currentCategoryIdAndChildren)
{ IsInCategory = IsInCategory.Or(pl => pl.categories.Any(c => categoryID == c.categoryid)); }
products = products.Where(IsInCategory);
This got me a bit better performance with my initial query, and MUCH better performance with subsequent queries.