【问题标题】:Linq to SQL assistance with joinsLinq to SQL 辅助连接
【发布时间】:2023-03-24 17:38:01
【问题描述】:

请你帮我把下面的 SQL 查询翻译成 LINQ 它主要是我遇到问题的连接。 结果将是执行的 LINQ to SQL 代码。

非常感谢

SELECT * FROM   unit INNER JOIN   

 unit_measurement_total ON unit.prime_measurement_uri = unit_measurement_total.uri RIGHT OUTER JOIN
   property_expense_schedule 
        INNER JOIN
     unit_apportionment ON property_expense_schedule.uri = unit_apportionment.property_expense_schedule_uri 
        INNER JOIN
      unit_apportionment_date ON unit_apportionment.uri = unit_apportionment_date.unit_apportionment_uri ON 
     unit_measurement_total.property_ref = unit_apportionment.property_ref
        WHERE (property_expense_schedule.property_ref = ...) 

这是我目前拥有的 LINQ,但它不会生成与 SQL 查询相同的结果。所以我在连接和正确的外部连接上出错了。

 var query = (from units in context.units
                 join unitmestot in context.unit_measurement_total on units.prime_measurement_uri equals unitmestot.uri
                 from pes in context.property_expense_schedule
                 join unitapp in context.unit_apportionment on new { A = pes.uri, B = unitmestot.property_ref, C = unitmestot.unit_ref } equals new { A = unitapp.property_expense_schedule_uri, B = unitapp.property_ref, C = unitapp.unit_ref}
                 join unitappdate in context.unit_apportionment_date on unitapp.uri equals unitappdate.unit_apportionment_uri
                 select new Apportionment()
                 {
                     PropertyRef = units.property_ref.ToString(),
                     ScheduleName = pes.name,
                     ScheduleRef = pes.@ref.ToString(),
                     PropertyExpenseScheduleUri = pes.uri,
                     UnitRef = units.@ref.ToString(),
                     UnitName = "(" + units.@ref.ToString() + ")" + units.name,
                     ObseleteUnit = units.obsolete_unit,
                     ApportionmentPercentage = unitappdate.apportionment_percentage,
                     ToDate = unitappdate.to_date,
                     MeasurementBasis = unitmestot.measurement_basis,
                     MeasuredIn = unitmestot.measured_in,
                     MeasurementImperialTotal = unitmestot.measurement_imperial_total,
                     MeasurementMetricTotal = unitmestot.measurement_metric_total

                 }).Where(filter);

您提供的最新代码生成以下 SQL 并返回 0 行。

  SELECT     [Extent1].[uri] AS [uri],     CASE WHEN ([Join3].[property_ref1] IS NULL) THEN N'' ELSE  CAST( [Join3].[property_ref1] AS nvarchar(max)) END AS [C1],     [Extent3].[name] AS [name],      CAST( [Extent3].[ref] AS nvarchar(max)) AS [C2],     [Extent3].[uri] AS [uri1],     CASE WHEN ([Join3].[ref] IS NULL) THEN N'' ELSE  CAST( [Join3].[ref] AS nvarchar(max)) END AS [C3],     N'(' + CASE WHEN (CASE WHEN ([Join3].[ref] IS NULL) THEN N'' ELSE  CAST( [Join3].[ref] AS nvarchar(max)) END IS NULL) THEN N'' WHEN ([Join3].[ref] IS NULL) THEN N'' ELSE  CAST( [Join3].[ref] AS nvarchar(max)) END + N')' + CASE WHEN ([Join3].[name] IS NULL) THEN N'' ELSE [Join3].[name] END AS [C4],     [Join3].[obsolete_unit] AS [obsolete_unit],     [Extent2].[apportionment_percentage] AS [apportionment_percentage],     [Extent2].[to_date] AS [to_date],     CASE WHEN ([Join3].[measurement_basis] IS NULL) THEN N'' ELSE [Join3].[measurement_basis] END AS [C5],     CASE WHEN ([Join3].[measured_in] IS NULL) THEN N'' ELSE [Join3].[measured_in] END AS [C6],     [Join3].[measurement_imperial_total] AS [measurement_imperial_total],     [Join3].[measurement_metric_total] AS [measurement_metric_total]    FROM    [tramps].[unit_apportionment] AS [Extent1]    INNER JOIN [tramps].[unit_apportionment_date] AS [Extent2] ON [Extent1].[uri] = [Extent2].[unit_apportionment_uri]    INNER JOIN [tramps].[property_expense_schedule] AS [Extent3] ON [Extent1].[property_expense_schedule_uri] = [Extent3].[uri]    LEFT OUTER JOIN  (SELECT [Extent4].[property_ref] AS [property_ref2], [Extent4].[measurement_basis] AS [measurement_basis], [Extent4].[measured_in] AS [measured_in], [Extent4].[measurement_imperial_total] AS [measurement_imperial_total], [Extent4].[measurement_metric_total] AS [measurement_metric_total], [Extent5].[property_ref] AS [property_ref1], [Extent5].[ref] AS [ref], [Extent5].[name] AS [name], [Extent5].[obsolete_unit] AS [obsolete_unit]        FROM  [tramps].[unit_measurement_total] AS [Extent4]        INNER JOIN [tramps].[unit] AS [Extent5] ON [Extent4].[uri] = [Extent5].[prime_measurement_uri] ) AS [Join3] ON [Extent1].[property_ref] = [Join3].[property_ref2]    WHERE (N'101329' = (CASE WHEN ([Join3].[property_ref1] IS NULL) THEN N'' ELSE  CAST( [Join3].[property_ref1] AS nvarchar(max)) END)) AND ( NOT (('Y' = [Join3].[obsolete_unit]) AND ([Join3].[obsolete_unit] IS NOT NULL)))

【问题讨论】:

  • 您能否举例说明您尝试过的方法以及遇到的具体问题?现在,您要求人们为您编写代码。
  • 我已经更新了问题
  • 我认为你可以使用linqpad.net 来学习曲线,这只是学习不太复杂的问题。
  • 你应该使用DefaultIfEmpty来表达right outer join
  • 感谢我使用 linq pad 来理解这一切,这就是我制作 LINQ 的方式。如果将生成的 SQL 重新操作为原始 SQL,它应该返回相同的结果??

标签: c# sql sql-server linq join


【解决方案1】:

LINQ不支持Right Outer Join,所以应该通过交换左右部分并执行Left Outer Join来模拟(这不太自然,但至少是已知的模式 - join clause (C# Reference))。

话虽如此,我认为等效的 LINQ 查询应该是这样的:

from unitapp in context.unit_apportionment
    join unitappdate in context.unit_apportionment_date on unitapp.uri equals unitappdate.unit_apportionment_uri
    join pes in context.property_expense_schedule on unitapp.property_expense_schedule_uri equals pes.uri
    join unitmestot in context.unit_measurement_total on unitapp.property_ref equals unitmestot.property_ref
        into unitapp_unitmesstot from unitmestot in unitapp_unitmesstot.DefaultIfEmpty() // Left Outer Join
    join units in context.units on unitmestot.uri equals units.prime_measurement_uri
       select new Apportionment()
       {
           // ...
       }

编辑:看起来 EF 在左外连接之后立即为内连接生成附加条件,这导致与原始 SQL 查询的差异。在这种情况下,您可以尝试将正确的部分分组到子查询中以尝试更改连接顺序:

    from unitapp in context.unit_apportionment
    join unitappdate in context.unit_apportionment_date on unitapp.uri equals unitappdate.unit_apportionment_uri
    join pes in context.property_expense_schedule on unitapp.property_expense_schedule_uri equals pes.uri
    join right in (
        from unitmestot in context.unit_measurement_total
        join units in context.units on unitmestot.uri equals units.prime_measurement_uri
        select new { unitmestot, units } 
    ) on unitapp.property_ref equals right.unitmestot.property_ref
    into outerJoin from right in outerJoin.DefaultIfEmpty() // Left Outer Join
    let unitmestot = right.unitmestot
    let units = right.units
    select new Apportionment()
    {
       // ...
    }

【讨论】:

  • 谢谢,但还是不对。与 SQL 表的顺序相比,您认为 LINQ 表的顺序重要吗?
  • 对于内部连接,它真的没关系。对于外部连接,这当然很重要。有什么区别 - 返回更少的记录?顺便说一句,是 LINQ to Entities 吗?你能添加var sql = query.ToString(); 并发布结果吗?
  • 由于网站规则,我不得不拒绝您的编辑 - 您应该将其作为更新发布在您的问题中。无论如何,我在生成的 sql 的最后一个内部连接中看到了可能导致差异的附加条件。我会用替代方法更新答案,但不幸的是无法测试它,因为它真的取决于我没有的实体模型。
  • 哦,好的,抱歉不知道规则,下次知道就好。是的,更新的代码将不胜感激。当然我明白,我可以测试它。谢谢。
  • 不幸的是它返回了 0 行,我已将生成的 SQL 作为编辑发布。在 LINQ 中肯定可以进行 SQL 查询吗?
猜你喜欢
  • 1970-01-01
  • 2012-10-24
  • 1970-01-01
  • 1970-01-01
  • 2014-04-08
  • 2014-08-25
  • 2011-10-14
  • 1970-01-01
相关资源
最近更新 更多