我正在寻找一种方法来查询目录中的产品,使用根据产品所属类别分配给产品的属性过滤器。所以我涉及以下实体:
产品-Id -CategoryId
类别[Id,Name,UrlName]
属性[Id,CategoryId,Name,UrlName]
PropertyValues [Id,PropertyId,Text,UrlText]
ProductPropertyValues [ProductId,PropertyValueId]
当我将产品添加到目录时,将根据类别添加多个ProductPropertyValues,我希望能够通过选择一个或多个属性的值来过滤类别中的所有产品。业务逻辑和SQL索引和约束确保所有UrlNames和文本对于值属性和类别都是唯一的。
解决方案将是基于MVC3 EF代码的第一个应用程序,路由设置如下:
/products/{categoryUrlName}/{*filters}
滤波器路由部分具有可变长度,因此可以应用多个滤波器。每个过滤器都包含属性的UrlName和由下划线分隔的值的UrlText。
网址可能如下/ products / websites / framework_mvc3 / language_csharp
我将通过阅读URL收集我将在列表中保存的所有过滤器。现在是时候实际获得基于多个属性的产品了,我一直在努力找到正确的策略。
也许有另一种方法来实现过滤器。所有较大的网上商店都使用依赖于类别的过滤器,我仍在寻找实现此类功能的持久性部分的最佳方法。如果选择了多个过滤器,则建议的解决方案会生成“或”结果集。我可以想象,将一个text属性添加到product表中,其中所有属性值都存储为连接字符串也可以。我不知道这会花费多少性能。在租用时,将不会有复杂的连接,无论如何,属性及其值将作为文本接收。
也许过滤机制可以很好地完成客户端。
关于这一点的棘手部分是将整个列表作为过滤器发送到数据库中。您构建越来越多where子句的方法可以起作用:
productsInCategory = ProductRepository
.Where(p => p.Category.Name == category);
foreach (PropertyFilter pf in filterList)
{
PropertyFilter localVariableCopy = pf;
productsInCategory = from product in productsInCategory
where product.ProductProperties
.Any(pp => pp.PropertyValueId == localVariableCopy.ValueId)
select product;
}
另一种方法是使用List.Contains方法发送整个列表
List<int> valueIds = filterList.Select(pf => pf.ValueId).ToList();
productsInCategory = ProductRepository
.Where(p => p.Category.Name == category)
.Where(p => p.ProductProperties
.Any(pp => valueIds.Contains(pp.PropertyValueId)
);
IEnumerable<int> filters = filterList.Select(pf => pf.ValueId);
var products = from pp in ProductPropertyRepository
where filters.Contains(pp.PropertyValueId)
&& pp.Product.Category.Name == category
select pp.Product;
请记住,当使用Contains
时,过滤器将作为sproc参数传递,这意味着必须注意不要超过sproc参数限制。
我提出了一个解决方案,即使我能理解......通过使用'Contains'方法,您可以根据需要链接尽可能多的WHERE。如果WHERE是一个空字符串,则忽略它(或者将其评估为全选)。这是我在LINQ中连接2个表的示例,应用多个where子句并填充要返回到视图的模型类。
public ActionResult Index()
{
string AssetGroupCode = "";
string StatusCode = "";
string SearchString = "";
var mdl = from a in _db.Assets
join t in _db.Tags on a.ASSETID equals t.ASSETID
where a.ASSETGROUPCODE.Contains(AssetGroupCode)
&& a.STATUSCODE.Contains(StatusCode)
&& (
a.PO.Contains(SearchString)
|| a.MODEL.Contains(SearchString)
|| a.USERNAME.Contains(SearchString)
|| a.LOCATION.Contains(SearchString)
|| t.TAGNUMBER.Contains(SearchString)
|| t.SERIALNUMBER.Contains(SearchString)
)
select new AssetListView
{
AssetId = a.ASSETID,
TagId = t.TAGID,
PO = a.PO,
Model = a.MODEL,
UserName = a.USERNAME,
Location = a.LOCATION,
Tag = t.TAGNUMBER,
SerialNum = t.SERIALNUMBER
};
return View(mdl);
}
我知道这是一个古老的答案,但如果有人看到这个我已经建立了这个项目:
https://github.com/PoweredSoft/DynamicLinq
哪个也应该可以在nuget上下载:
https://www.nuget.org/packages/PoweredSoft.DynamicLinq
您可以使用它来遍历来自查询字符串的过滤器并执行某些操作
query = query.Query(q =>
{
q.Compare("AuthorId", ConditionOperators.Equal, 1);
q.And(sq =>
{
sq.Compare("Content", ConditionOperators.Equal, "World");
sq.Or("Title", ConditionOperators.Contains, 3);
});
});