ASP.NET Core MVC中如何对继承自抽象类的Product对象实现安全筛选?
解决方案
以下方案从改造成本由低到高排列,可根据项目实际情况选择:
方案1:模式匹配快速实现(无需修改现有实体结构)
直接使用C#原生类型模式匹配,无反射性能损耗,代码简洁,EF Core也可正常解析为SQL语句:
// 筛选重量大于5kg的商品,自动过滤无Weight属性的类型 var filteredProducts = products .Where(p => p is ProductB b && b.Weight > 5) .ToList(); // 如需直接拿到匹配类型的集合,可使用OfType var matchedProductB = products.OfType<ProductB>().Where(b => b.Weight >5).ToList();
缺点:如果后续新增其他带Weight属性的商品子类,需要同步修改筛选条件的匹配逻辑。
方案2:提取公共属性接口(推荐,可维护性最高)
针对跨子类的通用属性,抽离独立接口标记对应类型,后续新增商品无需修改已有筛选逻辑:
- 定义属性接口
public interface IHasWeight { double Weight { get; set; } }
- 让所有带重量属性的商品类实现该接口
public class ProductB : Product, IHasWeight { public double Weight { get; set; } } // 后续新增带Weight的商品类型,只要实现接口即可,无需修改筛选代码 public class ProductC : Product, IHasWeight { public double Weight { get; set; } public string Material { get; set; } }
- 统一筛选逻辑
var filteredProducts = products .OfType<IHasWeight>() // 自动过滤所有未实现IHasWeight的类型 .Where(p => p.Weight > 5) .Cast<Product>() // 如需转回Product类型可加这一步 .ToList();
优势:完全解决新增商品要修改筛选分支的问题,性能无额外损耗,同时支持IEnumerable和IQueryable场景。同理需要按长宽筛选时,可定义IHasDimension接口封装Height、Width属性。
方案3:规格模式(适合复杂多条件筛选场景)
如果筛选规则多、组合逻辑复杂,可将每个筛选规则封装为独立规格类,上层业务只需组合规则即可:
public interface ISpecification<T> { bool IsSatisfiedBy(T entity); Expression<Func<T, bool>> ToExpression(); } public class WeightGreaterThanSpecification : ISpecification<Product> { private readonly double _minWeight; public WeightGreaterThanSpecification(double minWeight) => _minWeight = minWeight; public bool IsSatisfiedBy(Product entity) { return entity is IHasWeight hasWeight && hasWeight.Weight > _minWeight; } public Expression<Func<Product, bool>> ToExpression() { return p => p is IHasWeight hasWeight && hasWeight.Weight > _minWeight; } }
使用示例:
var spec = new WeightGreaterThanSpecification(5); var filtered = products.Where(spec.ToExpression()).ToList();
架构备选方案:放弃继承改用属性组合
如果商品属性非常灵活,后续会新增大量不同属性的商品类型,可放弃类继承方案,改为通用Product类+动态属性存储的结构:
public class Product { public string Name { get; set; } public double Price { get; set; } public ProductType Type { get; set; } // 内存场景用字典存扩展属性,数据库场景可对应JSON字段/关联属性表 public Dictionary<string, object> Attributes { get; set; } = new(); }
筛选时直接从属性集合取值即可,EF Core 7+已原生支持JSON属性查询,可适配数据库端筛选场景。
内容的提问来源于stack exchange,提问作者MrMeatballGuy
相关产品推荐
相关产品推荐

