【问题标题】:How to do Product Complex Filtering in SQL / Net Core如何在 SQL / Net Core 中进行产品复杂过滤
【发布时间】:2019-08-03 19:11:54
【问题描述】:

我有一个 Net Core 2.2 Web 应用程序、SQL Server 2017、Linq、Entity Core、SQLQuery FromSql

我需要对电子商务网站等产品进行复杂的过滤,您可以在其中按属性过滤笔记本电脑(品牌:戴尔、惠普、内存:2 GB、4 GB)

示例:(戴尔品牌或惠普品牌)和(S 码或 XL 码)。

我在选择多个属性后尝试使用产品数量(Count)显示属性和值时遇到问题(例如:选择 2 GB 或 4 GB 后的戴尔(4 件商品))

属性/过滤器:

Brand
- Dell (2 items)
- HP (3)

Memory
- 2 GB (2)
- 4 GB(3)

Display
- 17 inch (1)
- 19 inch ( 2)

因为在 LINQ 中无法实现,所以必须使用字符串 SQLQuery FromSql 来完成

SQL 数据库结构:

**Products** ( Ex: Laptop 1, Laptop 2 ) 
- ProductID

**Attributes** ( Ex: Memory, Brand ) 
- AttributeID

**AttributeValues** ( Ex: 2 Gb, Dell )
- AttributeValueID
- AttributeID ( foreign key )

**ProductAttributes** 
-ProductAttibuteID
-ProductID ( foreign key )
-AttributeID (  foreign key )
-AttributeValueID ( foreign key )

我已经尝试了一些东西,但没有工作并不算好:


 public class Filter
    {
        public int AtributeID { get; set; }
        public int ?AtributeValueID { get; set; }       
    }


// Filters - list with selected attributes ( AtributeID ,AtributeValueID )

string SQLQuery = "SELECT AtributeValueID,Title,Importance,AtributeID , (select count (*) from Products p where p.ProductCategoryID ={0}";

foreach (var filtersGroup in Filters.GroupBy(p => p.AtributeID))
{
    int atributeID = filtersGroup.Key;
    var atributeValues = filtersGroup.Select(p => p.AtributeValueID).ToList();

    SQLQuery += "and exists ( select 1 from ProductAtributes pa where pa.ProductID=p.ProductID and  ((av.AtributeID = " + atributeID + " and pa.AtributeValueID = av.AtributeValueID) ";

    foreach (var atributeValueID in atributeValues)
    {
        SQLQuery += " or pa.AtributeValueID=" + atributeValueID;
    }

    SQLQuery += "))";
}

SQLQuery += ") as Count";

SQLQuery += " FROM AtributeValues av ";


var queryAtributesValuesResult = context.Query<AtributeValueDTO>()
.FromSql(SQLQuery)
.AsNoTracking()
.ToList();

Executed DbCommand (1,203ms)
SELECT AtributeValueID,Title,Importance,AtributeID, 
(
    select count (*) from Products p where 
        exists 
        ( 
            select 1 from ProductAtributes pa where pa.ProductID=p.ProductID  
                                                    and ((av.AtributeID = 15 and pa.AtributeValueID = av.AtributeValueID) or pa.AtributeValueID=130)        
        )            
        and exists 
        ( 
            select 1 from ProductAtributes pa where pa.ProductID=p.ProductID 
                                                    and  ((av.AtributeID = 27 and pa.AtributeValueID = av.AtributeValueID) or pa.AtributeValueID=273 or pa.AtributeValueID=325)
        )      
)as Count 
FROM AtributeValues av

【问题讨论】:

  • LINQ 非常适合动态构建复杂的条件查询。显示您的实体。
  • 我使用 SQL Server 2017 。服务器位于 Azure 中。是的,上下文是实体核心框架。是的,我知道 Linq 不能在这种情况下使用,这就是为什么我们的重点是编写查询、视图或除 SQL 之外的其他内容的原因
  • 问题解决了吗?如果没有,请在 C# 中显示您的实体,我将在 LINQ 中给出解决方案。
  • 不,没有解决。实体与数据库结构相同:产品(例如:Laptop 1、Laptop 2)- ProductID Attributes(例如:内存、品牌)- AttributeID AttributeValues(例如:2 Gb,Dell)- AttributeValueID - AttributeID(外键) ProductAttributes -ProductAttibuteID -ProductID(外键) -AttributeID(外键) -AttributeValueID(外键)

标签: sql asp.net-core filter


【解决方案1】:

您的 ProductAtributes 包含其他表中的所有列,试试这个来获取产品 其中有 attr15=val130 和 attr27 = 273 或 325

select pa1.*, pa2.AtributeID, pa2.AtributeValueID
  , dense_rank() over (order by id pa1.ProductId) 
    + dense_rank() over (order by id pa1.ProductId desc) - 1 as productCount
from ProductAtributes pa1 
join ProductAtributes pa2 on pa1.ProductId = pa2.ProductId
  and pa1.AtributeID = 15 and pa1.AtributeValueID in (130) 
  and pa2.AtributeID = 27 and pa2.AtributeValueID in (273, 325)   

通常,您需要与请求的属性一样多的 JOIN 来恢复虚拟“具有属性集的产品”关系,然后根据需要应用属性谓词。

编辑添加了基于分析函数的表达式来计算产品。 Sql server 不支持analytic COUNT 中的DISTINCT 选项。所以我使用DENSE_RANK,但它不支持需要的窗口框架rows between unbounded preceding and unbounded following,我使用pa1.ProductId之前和之后的2个默认框架的总和。

【讨论】:

  • 谢谢。如何同时计算与过滤器关联的产品?我建议的数据库结构可以吗?我应该重组它吗?使用另一个临时表以更方便的方式重组数据以获得更高的性能?或者可能是 SQL 中的物化视图或 Json 数据?欢迎任何建议
  • 你会在谷歌上搜索“eav db design”找到很多优缺点。我的经验法则是在绝对不可避免之前不要走 EAV 路径。请参阅有关计数的更新。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-22
  • 2021-01-15
  • 1970-01-01
  • 2013-12-05
相关资源
最近更新 更多