Reputation: 819
I am building an asp.net website with ms-sql db for products - each product belongs to one or more categories and each categories can belong to one or zero parent categories.
The user should be able to select zero or many categories, but i can't figure out a way to only return products in the selected categories.
i've got other filters which are working (minimum price, brand name etc) but cant' get the categories to work.
For example:
-Category 1
|---Sub-Category 1.1
|---Sub-Sub-Category 1.1.1
|---Sub-Sub-Category 1.1.2
|---Sub-Category 1.2
|---Sub-Category 1.3
If Category 1 is selected, then all products that have a category where the Ultimate Parent is Category 1 should be returned.
If Sub-Category 1.1 and Sub-Category 1.2 is selected then all products that have a category where the Ultimate Parent is either Sub-Category 1.1 OR Sub-Category 1.2 should be returned.
This is my Code:
Product:
public class Product
{
[Key]
public int ProductID { get; set; }
public string Description {get;set;}
public double Price {get;set;}
public virtual List<Category> Categories { get; set; }
public Product()
{
Categories = new List<Category>();
}
}
Category:
public class Category
{
[Key]
public int CategoryID { get; set; }
public string CategoryName { get; set; }
public int? ParentCategoryID { get; set; }
[JsonIgnore]
public Category Parent { get; set; }
[JsonIgnore]
public virtual List<Product> Products { get; set; }
}
Simplified WebApi Controller:
public object Get( [FromUri] string[] categories)
{
List<Product> search_results = (from p in db.Products
where 1==1
&& p.Price >= minPrice && p.Price <=maxPrice
// only return products in selected categories
select p).ToList();
}
Upvotes: 0
Views: 2408
Reputation: 1879
If you have no limits on sub categories, you can use recursion:
public object Get( [FromUri] string[] categories)
{
var categories = db.Categories.Where(c => categoriesIds.Contains(c.Id));
Func<Product, bool> filters = p => 1==1
&& p.Price >= minPrice && p.Price <=maxPrice
return GetCategoryiesProducts(categories, filters)
}
public IList<Product> GetCategoryiesProducts(IList<Category> categories, Func<Product, bool> filters)
{
var result = new List<Product>();
foreach (var c in categories)
{
result.AddRange(c.Products.Where(filters).ToList());
var subCategories = db.Categories.Where(s => s.ParentCategoryID != null && (int)s.ParentCategoryID == c.Id))
if (subCategories != null && subCategories.Count > 0)
{
result.AddRange(GetCategoryiesProducts(subCategories, filters))
}
}
List<Product> search_results result;
}
but if there be a lot of categories it will be expensive solution. To optimize for efficiency you can add product to each parent categories to eliminate recursion:
List<Product> search_results = (from p in db.Products
where 1==1
&& p.Price >= minPrice && p.Price <=maxPrice
&& p.Categories.Any(c => categoriesIds.Contains(c.Id))
select p).ToList();
Upvotes: 1