【问题标题】:Search by correlated entity按关联实体搜索
【发布时间】:2016-02-07 00:25:46
【问题描述】:

您好,我正在为我的项目使用MVC 5Entity 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 );

但在这种情况下,我的问题是关于表演的。此查询在使用许多过滤器时表现如何?

【问题讨论】:

  • 如果您只是查询产品(而不关心标签的具体类型),您只需查询(抽象)标签数据库集。
  • @AlexKrupka:感谢您的回答。不幸的是,我需要考虑具体类型

标签: c# entity-framework asp.net-mvc-5 linq-to-entities


【解决方案1】:

如果您检查为您的查询生成的 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,它适用于“产品”表的所有列。您可能想查看自己的实际执行计划,这可能取决于很多事情。

在我这边,我看到的是 SQL Server 执行第一个查询,然后在结果上它调用“不同排序”,然后为了进行实际相交,它与 @987654324 执行“左半连接” @ 和 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,其执行计划使用内连接(在主键上)。

但是,如果不先检查您是否有性能问题,我实际上不会开始这个优化过程。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-09-04
    • 1970-01-01
    • 2019-01-04
    • 2021-12-14
    • 2018-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多