[英]How to perform filtering based on navigational properties EFCore
在我的项目中,我有一个 Box 实体:
public class Box : BaseEntity
{
public string Name { get; set; }
public BoxSize Size { get; set; } = BoxSize.Small;
public BoxColor Color { get; set; } = BoxColor.Black;
public double Price { get; set; }
public int Stock { get; set; }
public List<Product> Products { get; set; }
}
其中有产品列表作为导航属性:
public class Product : BaseEntity
{
public string Name { get; set; }
...
public int ProductTypeId { get; set; }
public ProductType ProductType { get; set; }
public int ProductBrandId { get; set; }
public ProductBrand ProductBrand { get; set; }
public int? BoxId { get; set; }
public Box Box { get; set; }
public int CategoryId { get; set; }
public Category Category { get; set; }
}
在过滤盒子时,我必须按品牌、类型或里面的产品类别来过滤它们。 为了过滤,我使用了一个单独的 object ProductParams:
public class ProductParams
{
...
public int? BrandId { get; set; }
public int? TypeId { get; set; }
public int? CategoryId { get; set; }
public string Sort { get; set; }
private string _search;
public string Search
{
get => _search;
set => _search = value.ToLower();
}
}
这段代码描述了行动的想法:
var result = new List<Box>();
foreach (var box in boxes)
{
bool isSearch = false, isType = false, isBrand = false, isCategory = false;
foreach (var product in box.Products)
{
if (!string.IsNullOrEmpty(productParams.Search))
{
if (product.Name.ToLower().Contains(productParams.Search.ToLower()))
isSearch = true;
}
else
isSearch = true;
if (productParams.TypeId != null)
{
if (product.ProductTypeId == productParams.TypeId)
isType = true;
}
else
isType = true;
if (productParams.BrandId != null)
{
if (product.ProductBrandId == productParams.BrandId)
isBrand = true;
}
else
isBrand = true;
if (productParams.CategoryId != null)
{
if (product.CategoryId == productParams.CategoryId)
isCategory = true;
}
else
isCategory = true;
}
if (isSearch && isType && isBrand && isCategory)
result.Add(box);
我想知道是否可以将上面的代码实现为 Linq 查询,因为存在双循环。 例如:
var boxes = _context.Boxes
.Include(b => b.Products)
.ThenInclude(p => p.ProductBrand)
.Include(b => b.Products)
.ThenInclude(p => p.ProductType)
.Include(b => b.Products)
.ThenInclude(p => p.Category)
.Where(***/// Some code I am looking for using ProductParams///***)
.ToList();
是的,您可以使用 LINQKit 库中的PredicateBuilder
来做到这一点:
从示意图上看,它应该如下所示:
var query = _context.Boxes
.Include(b => b.Products)
.ThenInclude(p => p.ProductBrand)
.Include(b => b.Products)
.ThenInclude(p => p.ProductType)
.Include(b => b.Products)
.ThenInclude(p => p.Category)
.AsQueryable();
var predicate = PredicateBuilder.Create<Box>();
if (!string.IsNullOrEmpty(productParams.Search))
predicate = predicate.And(box => box.Products.Any(product => product.Name.ToLower().Contains(productParams.Search.ToLower())));
if (productParams.TypeId != null)
predicate = predicate.And(box => box.Products.Any(product => product.ProductTypeId == productParams.TypeId));
if (productParams.BrandId != null)
predicate = predicate.And(box => box.Products.Any(product => product.ProductBrandId == productParams.BrandId));
if (productParams.CategoryId != null)
predicate = predicate.And(box => box.Products.Any(product => product.CategoryId == productParams.CategoryId));
var result = query.Where(predicate).ToList();
检查性能,如果它无效,最好通过 GroupBy 来做。 我假设您使用的是 EF Core 5.x:
var query = _context.Boxes
.Include(b => b.Products)
.ThenInclude(p => p.ProductBrand)
.Include(b => b.Products)
.ThenInclude(p => p.ProductType)
.Include(b => b.Products)
.ThenInclude(p => p.Category)
.AsQueryable();
var grouped = context.Products
.Where(product => product.BoxId != null)
.GroupBy(product => product.BoxId)
.Select(g => new
{
BoxId = g.Key,
IsSearch = productParams.Search == null || productParams.Search == '' ? true :
g.Count(product => product.Name.ToLower().Contains(productParams.Search.ToLower()) > 0,
IsType = productParams.TypeId == null ? true :
g.Count(product => product.ProductTypeId == productParams.TypeId) > 0,
IsBrand = productParams.BrandId == null ? true :
g.Count(product => product.ProductBrandId == productParams.BrandId) > 0,
IsCategory = productParams.CategoryId == null ? true : ;
g.Count(product => product.CategoryId == productParams.CategoryId) > 0
})
.Where(g => g.IsSearch && g.IsType && g.IsBrand && g.IsCategory)
var result = query
.Join(grouped, box => box.Id, g => g.BoxId, (box, g) => box)
.ToList()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.