【问题标题】:Linq to entities - One to many relationship - need left outer join instead of cross joinLinq to entity - 一对多关系 - 需要左外连接而不是交叉连接
【发布时间】:2011-09-20 10:11:02
【问题描述】:

我有以下型号:

我需要一个特定用户的所有灯具和预测的列表(如果该灯具有预测)。返回我需要的sql如下:

SELECT * FROM Fixture f
LEFT OUTER JOIN Prediction p ON f.FixtureId = p.FixtureId
WHERE p.UserID = '06E4D3E0-8365-45BF-9054-3F8534C7AD5E' OR p.UserID IS NULL

我试过了:

var query = from f in c.Fixtures
    from p in c.Predictions.Where(pre => pre.UserId == new Guid("06E4D3E0-8365-45BF-9054-3F8534C7AD5E") || pre.UserId == null)
    select new
    {
        FixtureId = f.FixtureId,
        HomeScore = f.HomeTeamScore,
        AwayScore = f.AwayTeamScore,
        PredictionId = p.PredictionId,
        HomePrediction = p.HomeTeamPrediction,
        AwayPrediction = p.AwayTeamPrediction
        };

但这会产生(并给出错误的结果):

SELECT 
[Extent1].[FixtureId] AS [FixtureId], 
[Extent1].[HomeTeamScore] AS [HomeTeamScore], 
[Extent1].[AwayTeamScore] AS [AwayTeamScore], 
[Extent2].[PredictionId] AS [PredictionId], 
[Extent2].[HomeTeamPrediction] AS [HomeTeamPrediction], 
[Extent2].[AwayTeamPrediction] AS [AwayTeamPrediction]
FROM  [dbo].[Fixture] AS [Extent1]
CROSS JOIN [dbo].[Prediction] AS [Extent2]
WHERE cast('06e4d3e0-8365-45bf-9054-3f8534c7ad5e' as uniqueidentifier) = [Extent2].[UserId]

将DefaultIfEmpty 添加到第二个“来自”之类的:

var query = from f in c.Fixtures
    from p in c.Predictions.Where(pre => pre.UserId == new Guid("06E4D3E0-8365-45BF-9054-3F8534C7AD5E") || pre.UserId == null).DefaultIfEmpty()
    select new
    {
        FixtureId = f.FixtureId,
        HomeScore = f.HomeTeamScore,
        AwayScore = f.AwayTeamScore,
        PredictionId = p.PredictionId,
        HomePrediction = p.HomeTeamPrediction,
        AwayPrediction = p.AwayTeamPrediction
    };

生成(但仍然给出错误的结果):

SELECT 
[Extent1].[FixtureId] AS [FixtureId], 
[Extent1].[HomeTeamScore] AS [HomeTeamScore], 
[Extent1].[AwayTeamScore] AS [AwayTeamScore], 
[Join1].[PredictionId] AS [PredictionId], 
[Join1].[HomeTeamPrediction] AS [HomeTeamPrediction], 
[Join1].[AwayTeamPrediction] AS [AwayTeamPrediction]
FROM  [dbo].[Fixture] AS [Extent1]
CROSS JOIN  (SELECT [Project1].[PredictionId] AS [PredictionId], [Project1].[HomeTeamPrediction] AS [HomeTeamPrediction], [Project1].[AwayTeamPrediction] AS [AwayTeamPrediction]
FROM   ( SELECT 1 AS X ) AS [SingleRowTable1]
LEFT OUTER JOIN  (SELECT 
    [Extent2].[PredictionId] AS [PredictionId], 
    [Extent2].[UserId] AS [UserId], 
    [Extent2].[HomeTeamPrediction] AS [HomeTeamPrediction], 
    [Extent2].[AwayTeamPrediction] AS [AwayTeamPrediction]
    FROM [dbo].[Prediction] AS [Extent2]
    WHERE cast('06e4d3e0-8365-45bf-9054-3f8534c7ad5e' as uniqueidentifier) = [Extent2].[UserId] ) AS [Project1] ON 1 = 1 ) AS [Join1]

按原样使用现有关系(这是我出错的地方,请参阅下面的答案):

var query = from f in c.Fixtures
   from p in c.Predictions
   where c.Predictions.Any(pre => pre.UserId == new Guid("06E4D3E0-8365-45BF-9054-3F8534C7AD5E") || pre.UserId == null)
   select new
   {
      FixtureId = f.FixtureId,
      HomeScore = f.HomeTeamScore,
      AwayScore = f.AwayTeamScore,
      PredictionId = p.PredictionId,
      HomePrediction = p.HomeTeamPrediction,
      AwayPrediction = p.AwayTeamPrediction
   };

生成:

SELECT 
[Extent1].[FixtureId] AS [FixtureId], 
[Extent1].[HomeTeamScore] AS [HomeTeamScore], 
[Extent1].[AwayTeamScore] AS [AwayTeamScore], 
[Extent2].[PredictionId] AS [PredictionId], 
[Extent2].[HomeTeamPrediction] AS [HomeTeamPrediction], 
[Extent2].[AwayTeamPrediction] AS [AwayTeamPrediction]
FROM  [dbo].[Fixture] AS [Extent1]
CROSS JOIN [dbo].[Prediction] AS [Extent2]
WHERE  EXISTS (SELECT 
    1 AS [C1]
    FROM [dbo].[Prediction] AS [Extent3]
    WHERE cast('06e4d3e0-8365-45bf-9054-3f8534c7ad5e' as uniqueidentifier) = [Extent3].[UserId]
)

如何生成我需要的查询?

【问题讨论】:

  • 你把 DefaultIfEmpty 放在哪里了?你能告诉我们整个查询吗?
  • 编辑显示DefaultIfEmpty使用。
  • 您正在 linq 查询中进行交叉连接 ...
  • @Ladislav Mrnka,你说得对,我是,但我不知道为什么,请参阅 AakashM 的回答。

标签: c# sql linq linq-to-sql entity-framework-4.1


【解决方案1】:

EF 已经为你生成了导航属性,所以继续使用它们吧!

代替

var query = 
    from f in c.Fixtures
    from p in c.Predictions
        .Where(pre => pre.UserId == new Guid("06E4D3E0-8365-45BF-9054-3F8534C7AD5E") 
            || pre.UserId == null)

试试

var query = 
    from f in c.Fixtures
    from p in f.Predictions
        .Where(pre => pre.UserId == new Guid("06E4D3E0-8365-45BF-9054-3F8534C7AD5E") 
            || pre.UserId == null)

注意using join and DefaultIfEmpty is often a mistake in EF。

【讨论】:

  • 是的,我真的很想使用现有的关系,但我已经编辑了我的问题以显示您的建议的结果.. :(
  • @Sprintstar 不完全。第二个from 应该是f.Predictions,而不是c.Predictions。 c.Predictions 根本没有使用 导航属性!
  • 啊,我明白了!我没有使用关系,只是另一个,因此是交叉连接。
猜你喜欢
  • 2010-09-09
  • 2020-04-27
  • 1970-01-01
  • 2013-09-09
  • 2013-02-25
  • 2010-09-21
  • 2013-06-13
  • 1970-01-01
相关资源
最近更新 更多