gpt4 book ai didi

c# - 哪种设计模式用于过滤查询? C#

转载 作者:可可西里 更新时间:2023-11-01 09:02:38 24 4
gpt4 key购买 nike

我有一个包含产品(服装)列表的数据库表。产品属于类别,来自不同的商店。

示例类别:上衣、下装、鞋子

示例商店:gap.com、macys.com、target.com

我的客户可以通过以下方式请求过滤产品:

  • 所有产品(无过滤器)
  • 按类别
  • 按商店
  • 按类别和商店

现在我的“产品”类中有一个方法可以根据用户请求的过滤器类型返回产品。我使用 FilterBy 枚举来确定需要退回哪些产品。

例如,如果用户想查看“tops”类别中的所有产品,我调用此函数:

Products.GetProducts(FilterBy.Category, "tops", ""); 

我将最后一个参数设为空,因为它是包含筛选依据的“商店”的字符串,但在本例中没有商店。但是,如果用户想按类别过滤和存储,我会这样调用方法:

Product.GetProducts(FilterBy.CategoryAndStore, "tops", "macys.com");

我的问题是,执行此操作的更好方法是什么?我刚刚了解了策略设计模式。我可以用它以更好(更容易扩展和维护)的方式来做到这一点吗?

我问这个问题的原因是因为我认为这一定是人们反复解决的一个非常普遍的问题(以各种方式过滤产品)

最佳答案

根据 Eric Evan 的“域驱动设计”,您需要规范模式。像这样

public interface ISpecification<T>
{
bool Matches(T instance);
string GetSql();
}

public class ProductCategoryNameSpecification : ISpecification<Product>
{
readonly string CategoryName;
public ProductCategoryNameSpecification(string categoryName)
{
CategoryName = categoryName;
}

public bool Matches(Product instance)
{
return instance.Category.Name == CategoryName;
}

public string GetSql()
{
return "CategoryName like '" + { escaped CategoryName } + "'";
}
}

现在可以使用规范调用您的存储库

var specifications = new List<ISpecification<Product>>();
specifications.Add(
new ProductCategoryNameSpecification("Tops"));
specifications.Add(
new ProductColorSpecification("Blue"));

var products = ProductRepository.GetBySpecifications(specifications);

您还可以创建一个通用的 CompositeSpecification 类,该类将包含子规范和一个指示器,指示将哪个逻辑运算符应用于它们 AND/OR

不过,我更倾向于组合 LINQ 表达式。

更新 - 运行时的 LINQ 示例

var product = Expression.Parameter(typeof(Product), "product");
var categoryNameExpression = Expression.Equal(
Expression.Property(product, "CategoryName"),
Expression.Constant("Tops"));

你可以像这样添加一个“和”

var colorExpression = Expression.Equal(
Expression.Property(product, "Color"),
Expression.Constant("Red"));
var andExpression = Expression.And(categoryNameExpression, colorExpression);

最后你可以把这个表达式转换成一个谓词然后执行它...

var predicate = 
(Func<Product, bool>)Expression.Lambda(andExpression, product).Compile();
var query = Enumerable.Where(YourDataContext.Products, predicate);

foreach(Product currentProduct in query)
meh(currentProduct);

可能不会编译,因为我直接在浏览器中输入了它,但我相信它通常是正确的。

另一个更新 :-)

List<Product> products = new List<Product>();
products.Add(new Product { CategoryName = "Tops", Color = "Red" });
products.Add(new Product { CategoryName = "Tops", Color = "Gree" });
products.Add(new Product { CategoryName = "Trousers", Color = "Red" });
var query = (IEnumerable<Product>)products;
query = query.Where(p => p.CategoryName == "Tops");
query = query.Where(p => p.Color == "Red");
foreach (Product p in query)
Console.WriteLine(p.CategoryName + " / " + p.Color);
Console.ReadLine();

在这种情况下,您将在内存中进行评估,因为源是一个列表,但如果您的源是支持 Linq2SQL 的数据上下文,例如我认为这将使用 SQL 进行评估。

您仍然可以使用规范模式来明确您的概念。

public class Specification<T>
{
IEnumerable<T> AppendToQuery(IEnumerable<T> query);
}

这两种方法的主要区别在于后者基于显式属性构建已知查询,而第一种方法可用于构建任何结构的查询(例如完全从 XML 构建查询。)

这应该足以让您入门 :-)

关于c# - 哪种设计模式用于过滤查询? C#,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/525370/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com