您好,我正在为我的项目使用 MVC 5
和 Entity Framework 6
。
我有一个如下图所示的模型:
我需要从一组 Tag
对象开始查询实体产品。
请注意,Tag
对象是一个抽象类,它实际上是通过使用Table-Per-Entity
策略继承来映射的。
这是我的函数方法的签名
public IEnumerable<Product> SerachByTag( IEnumerable<Tag> tagList );
在 tagList 参数中实际上会有 Tag
实现的具体实例。
我该如何查询?
例如我可以在输入中接收以下数据结构
[
{ tagType: 1, stringProperty: "abc" },
{ tagType: 2, intProperty: 9 }
]
等等。哪种过滤产品的方法更好?例如,我当然可以首先为每个标准应用一个产品列表,然后将这些结果相交,如以下示例所示:
var p1 = ctx.Tags
.OfType<FirstTagType>()
.Where( x => x.StringProperty.Equals("abc") )
.Select( x => x.Products );
var p2 = ctx.Tags
.OfType<SecondTagType>()
.Where( x => x.IntProperty == 9 )
.Select( x => x.Products );
var results = p1.Intersect( p2 );
但在这种情况下,我的问题是关于性能的。此查询如何处理多个过滤器?
最佳答案
如果检查为查询生成的 SQL,您会发现类似的内容:
SELECT
[Intersect1].[ProductId] AS [C1],
[Intersect1].[ProductName] AS [C2]
FROM (SELECT
[Extent3].[ProductId] AS [ProductId],
[Extent3].[ProductName] AS [ProductName]
FROM [dbo].[FirstTag] AS [Extent1]
INNER JOIN [dbo].[Tag] AS [Extent2] ON [Extent1].[TagId] = [Extent2].[TagId]
LEFT OUTER JOIN [dbo].[Product] AS [Extent3] ON [Extent2].[Product_ProductId] = [Extent3].[ProductId]
WHERE N'aaaa-9' = [Extent1].[StringProperty]
INTERSECT
SELECT
[Extent6].[ProductId] AS [ProductId],
[Extent6].[ProductName] AS [ProductName]
FROM [dbo].[SecondTag] AS [Extent4]
INNER JOIN [dbo].[Tag] AS [Extent5] ON [Extent4].[TagId] = [Extent5].[TagId]
LEFT OUTER JOIN [dbo].[Product] AS [Extent6] ON [Extent5].[Product_ProductId] = [Extent6].[ProductId]
WHERE -9 = [Extent4].[IntProperty]) AS [Intersect1]
在这里,您可以看到内部选择查询正在执行您期望的操作。连接是基于外键的,并且对于列上的索引应该是快速的。因此,如果您有很多过滤器,您只需确保它们都适用于正确索引的列。
LINQ Intersect
被转换为 SQL INTERSECT
,它作用于“product”表的所有列。您可能想查看您这边的实际执行计划,它可能取决于很多因素。
在我这边,我看到的是 SQL Server 执行第一个查询,然后在结果上调用“不同排序”,然后执行实际相交,它执行“左半连接”与 ProductId
和 ProductName
(因此 Product 表中的所有列)。这可能不是最好的,因为我的猜测是您没有在所有列上建立索引。
一种优化方法是仅在主键上进行交集(这应该很快),然后根据 id 获取所有产品数据:
var p1 = ctx.Tags
.OfType<FirstTag>()
.Where(x => x.StringProperty.Equals("aaaa-9"))
.Select(x => x.Product.ProductId);
var p2 = ctx.Tags
.OfType<SecondTag>()
.Where(x => x.IntProperty == -9)
.Select(x => x.Product.ProductId);
var query = ctx.Products.Where(p => p1.Intersect(p2).Contains(p.ProductId));
生成的底层 SQL 查询使用 EXISTS
并且其执行计划使用内部联接(在主键上)。
但是,如果不首先检查您是否存在性能问题,我不会真正开始这个优化过程。
关于c# - 按相关实体搜索,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33556929/