根据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"));
您可以这样添加“and”
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();
在这种情况下,你将会在内存中进行评估,因为源是一个 List,但如果你的源是支持 Linq2SQL 的数据上下文,比如说,我认为这个将会使用 SQL 进行评估。
你仍然可以使用规约模式来使你的概念更加明确。
public class Specification<T>
{
IEnumerable<T> AppendToQuery(IEnumerable<T> query);
}
两种方法的主要区别在于,后者基于显式属性构建已知查询,而前者可以用于构建任何结构的查询(例如完全从XML构建查询)。
这应该足以让你开始了 :-)