我有一个包含产品(服装)列表的数据库表。产品属于类别,来自不同的商店。
示例类别:上衣、下装、鞋子
示例商店: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/
我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co
我正在用Ruby编写一个简单的程序来检查域列表是否被占用。基本上它循环遍历列表,并使用以下函数进行检查。require'rubygems'require'whois'defcheck_domain(domain)c=Whois::Client.newc.query("google.com").available?end程序不断出错(即使我在google.com中进行硬编码),并打印以下消息。鉴于该程序非常简单,我已经没有什么想法了-有什么建议吗?/Library/Ruby/Gems/1.8/gems/whois-2.0.2/lib/whois/server/adapters/base.
大约一年前,我决定确保每个包含非唯一文本的Flash通知都将从模块中的方法中获取文本。我这样做的最初原因是为了避免一遍又一遍地输入相同的字符串。如果我想更改措辞,我可以在一个地方轻松完成,而且一遍又一遍地重复同一件事而出现拼写错误的可能性也会降低。我最终得到的是这样的:moduleMessagesdefformat_error_messages(errors)errors.map{|attribute,message|"Error:#{attribute.to_s.titleize}#{message}."}enddeferror_message_could_not_find(obje
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
我有一个围绕一些对象的包装类,我想将这些对象用作散列中的键。包装对象和解包装对象应映射到相同的键。一个简单的例子是这样的:classAattr_reader:xdefinitialize(inner)@inner=innerenddefx;@inner.x;enddef==(other)@inner.x==other.xendenda=A.new(o)#oisjustanyobjectthatallowso.xb=A.new(o)h={a=>5}ph[a]#5ph[b]#nil,shouldbe5ph[o]#nil,shouldbe5我试过==、===、eq?并散列所有无济于事。
鉴于我有以下迁移:Sequel.migrationdoupdoalter_table:usersdoadd_column:is_admin,:default=>falseend#SequelrunsaDESCRIBEtablestatement,whenthemodelisloaded.#Atthispoint,itdoesnotknowthatusershaveais_adminflag.#Soitfails.@user=User.find(:email=>"admin@fancy-startup.example")@user.is_admin=true@user.save!ende
我将应用程序升级到Rails4,一切正常。我可以登录并转到我的编辑页面。也更新了观点。使用标准View时,用户会更新。但是当我添加例如字段:name时,它不会在表单中更新。使用devise3.1.1和gem'protected_attributes'我需要在设备或数据库上运行某种更新命令吗?我也搜索过这个地方,找到了许多不同的解决方案,但没有一个会更新我的用户字段。我没有添加任何自定义字段。 最佳答案 如果您想允许额外的参数,您可以在ApplicationController中使用beforefilter,因为Rails4将参数
我知道我可以指定某些字段来使用pluck查询数据库。ids=Item.where('due_at但是我想知道,是否有一种方法可以指定我想避免从数据库查询的某些字段。某种反拔?posts=Post.where(published:true).do_not_lookup(:enormous_field) 最佳答案 Model#attribute_names应该返回列/属性数组。您可以排除其中一些并传递给pluck或select方法。像这样:posts=Post.where(published:true).select(Post.attr
我已经在Sinatra上创建了应用程序,它代表了一个简单的API。我想在生产和开发上进行部署。我想在部署时选择,是开发还是生产,一些方法的逻辑应该改变,这取决于部署类型。是否有任何想法,如何完成以及解决此问题的一些示例。例子:我有代码get'/api/test'doreturn"Itisdev"end但是在部署到生产环境之后我想在运行/api/test之后看到ItisPROD如何实现? 最佳答案 根据SinatraDocumentation:EnvironmentscanbesetthroughtheRACK_ENVenvironm
如何在ruby中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL