Reputation: 1035
I have this DB design (ProductCategories is a join table):
I need to query sold products, filter them by date, group by product ID and find all categories for that product. Plus some other details irrelevant for this question.
I have everything working except finding those categories.
My current working LINQ query looks like this:
var articles = await _context.PreordersProducts
.Where(...)
.GroupBy(p => new { p.Product.Code, p.Product.Id, Sum = p.Product.ProductVariants.Sum(v => v.InitialQuantity) })
.Select(p =>
new Article(
p.Key.Id,
p.Key.Code,
p.Key.Sum
))
.ToListAsync();
it gives me this result:
{
"id": 11111,
"code": "123-AAA",
"initialQuantity": 50,
}
and I need to add categories so the result will look like this:
{
"id": 11111,
"code": "123-AAA",
"initialQuantity": 50,
"categories": [
{
"id": 1,
"name": "category 1"
},
{
"id": 2,
"name": "category 2"
},
]
}
I had two ideas but neither of them can be translated to SQL.
One was adding Categories to GroupBy:
.GroupBy(p => new
{
p.Product.Code,
p.Product.Id,
Sum = p.Product.ProductVariants.Sum(v => v.InitialQuantity),
Categories = p.Product.ProductCategories.Select(c => c.Category)
})
Second was adding SelectMany to Select:
.Select(p =>
new
{
p.Key.Id,
p.Key.Code,
p.Key.Sum,
Categories = p.SelectMany(c => c.Product.ProductCategories.Select(cc => cc.Category))
})
I belive something like this would be possible in SQL, but this is far beyond my SQL knowledge.
So, could you please help me, how to write this in single query?
Classes:
public partial class Product
{
public int Id { get; private set; }
public string Name { get; private set; }
public string Code { get; private set; }
public virtual ICollection<PreorderProduct> PreorderProducts { get; private set; }
public virtual ICollection<ProductVariant> ProductVariants { get; private set; }
public virtual ICollection<ProductCategory> ProductCategories { get; private set; }
}
public partial class ProductVariant
{
public int Id { get; private set; }
public int ProductId { get; private set; }
public string Code { get; private set; }
public int InitialQuantity { get; private set; }
public virtual Product Product { get; private set; }
public virtual ICollection<PreorderProduct> PreorderProducts { get; private set; }
}
public partial class PreorderProduct
{
public int Id { get; private set; }
public int ProductId { get; private set; }
public int ProductVariantId { get; private set; }
public virtual Product Product { get; private set; }
public virtual ProductVariant ProductVariant { get; private set; }
}
public partial class ProductCategory
{
public int Id { get; private set; }
public int ProductId { get; private set; }
public int CategoryId { get; private set; }
public virtual Product Product { get; private set; }
public virtual Category Category { get; private set; }
}
public partial class Category
{
public int Id { get; private set; }
public string Name { get; private set; }
public virtual ICollection<ProductCategory> ProductCategories { get; private set; }
}
Upvotes: 2
Views: 821
Reputation: 27282
I hope I've got the idea
var filtered = _context.PreordersProducts
.Where(...);
var grouped =
from p in filtered
from v in p.Product.ProductVariants
group v by new { p.Product.Code, p.Product.Id } into g
select new
{
g.Key.Id,
g.Key.Code,
initialQuantity = g.Sum(x => x.InitialQuantity)
};
var query =
from g in grouped
select new
{
g.Id,
g.Code,
g.initialQuantity,
categories =_context.ProductCategories
.Where(x => x.ProductId == g.Id)
.Select(x => new { id = x.Category.Id, name = x.Category.Name })
.ToList()
}
var result = await query.ToListAsync();
Upvotes: 3
Reputation: 34421
Use following :
Product _context = new Product();
var articles = new
{
id = _context.Id,
code = _context.Code,
intialQuantity = _context.ProductCategories.Count(),
categories = _context.ProductCategories.Select(x => new { productId = x.Id, id = x.Category.Id, name = x.Category.Name }).ToList()
};
Upvotes: 0