繁体   English   中英

EF4.2额外的左外连接到同一个表

[英]EF4.2 extra left outer join to same table

我知道有一些关于这个的问题,大多数都与已解决的旧问题或多个表有关。 我看到的任何其他“左外连接”问题都没有涉及这个问题,我在同一个查询中得到一个INNER JOINLEFT OUTER JOIN到同一个表。

表格大纲:

Users: id (PK)
       Name (VARCHAR) 
       ProfileImageUri (VARCHAR)
Locations: id (PK)
LocationBPNTips: id (PK)
                 TipText (VARCHAR)
                 CreatedAt (Datetime)
                 UserId (int) (FK to User.id, navigation property is called User)
                 LocationId (int) (FK to Location.id)

(还有更多,但不相关:))

在我的场景中,我通过投影执行对引用表的查询,我得到一个额外的左外连接,这是我运行的( 注释部分与问题无关,注释掉更清晰的SQL,EF执行排序权限) (甚至比我想象的更好:))):

LocationBPNTips
     .Where(t => t.LocationId == 33)
     //.OrderByDescending(t => intList.Contains(t.UserId))
     //.ThenByDescending(t => t.CreatedAt)
     .Select(tip => new LocationTipOutput
     {
             CreatedAt = tip.CreatedAt,
             Text = tip.TipText,
             LocationId = tip.LocationId,
             OwnerName = tip.User.Name,
             OwnerPhoto = tip.User.ProfileImageUri
     }).ToList();

这就是生成的SQL

SELECT 
[Extent1].[LocationId] AS [LocationId], 
[Extent1].[CreatedAt] AS [CreatedAt], 
[Extent1].[TipText] AS [TipText], 
[Extent2].[Name] AS [Name], 
[Extent3].[ProfileImageUri] AS [ProfileImageUri]
FROM   [dbo].[LocationBPNTips] AS [Extent1]
INNER JOIN [dbo].[Users] AS [Extent2] ON [Extent1].[UserId] = [Extent2].[Id]
LEFT OUTER JOIN [dbo].[Users] AS [Extent3] ON [Extent1].[UserId] = [Extent3].[Id]
WHERE 33 = [Extent1].[LocationId]

如您所见, LEFT OUTER JOININNER JOIN的同一个表上完成

我认为最佳代码将是(注意,我手动将Extent3重命名为Extent2,并添加了注释。这不是由EF生成的!) - 使用我当前的数据,运行速度提高了约22%(排序时,这个%应该更高,没有排序),因为不需要额外的加入..

SELECT 
[Extent1].[LocationId] AS [LocationId], 
[Extent1].[CreatedAt] AS [CreatedAt], 
[Extent1].[TipText] AS [TipText], 
[Extent2].[Name] AS [Name], 
[Extent2].[ProfileImageUri] AS [ProfileImageUri]
FROM   [dbo].[LocationBPNTips] AS [Extent1]
INNER JOIN [dbo].[Users] AS [Extent2] ON [Extent1].[UserId] = [Extent2].[Id]
--LEFT OUTER JOIN [dbo].[Users] AS [Extent3] ON [Extent1].[UserId] = [Extent3].[Id]
WHERE 33 = [Extent1].[LocationId]

我尝试过的不同查询(投影是这些中的匿名类型):

LocationBPNTips
     .Where(t => t.LocationId == 33)
     //.OrderByDescending(t => intList.Contains(t.UserId))
     //.ThenByDescending(t => t.CreatedAt)
     .Select(tip => new 
     {
             CreatedAt = tip.CreatedAt,
             Text = tip.TipText,
             LocationId = tip.LocationId,
             OwnerName = tip.User,
             OwnerPhoto = tip.User
     }).ToList()

SQL输出搞砸了,它以与上面相同的格式选择整个用户表两次,内部然后左外部。 我认为我在理论上可以看到为什么会发生这种情况,因为我要求两次数据 - 尽管它可以在内存中完成,而不是由SQL进行额外的连接 - 但在我的情况下我没有要求数据两次,我只询问一次不同的列。 我做了这个测试,看看双连接是否一致。

我也试过跑:

LocationBPNTips
    .Where(t => t.LocationId == 33)
    .Select(tip => new 
    {
            CreatedAt = tip.CreatedAt,
            Text = tip.TipText,
            LocationId = tip.LocationId,
            OwnerName = tip.User.Name
    }).ToList()

这个按预期返回了干净的单内连接,但这不是我想要做的

所以问题是 :这是一个错误吗? 我错误地使用EF吗?

我已经看过类似的问题了。 我们可以称之为bug或功能。 简单的EF查询生成远非理想。 ADO.NET团队修复了每个主要版本的一些问题。 我目前没有安装June CTP 2011以验证它是否也出现在下一版本的第一个预览中。

编辑:

根据这个答案,类似的问题在2011年6月CTP修复。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM