首页 > 解决方案 > 应用于 edmx 实体数据模型时,LINQ 中的自联接失败

问题描述

我的 EF 模型中有以下两个表。一个设备可能有零个、一个或多个数据校准。

表“Equipo”:此表包含设备。主键是equioid

Id | equipoId  |  Description
1     9474
2     9473
3     9475

表“CalibracionVerificacion”:此表包含每个设备的校准数据(设备数据校准)。主键是 ID。

   Id | equipoId | magnitudId | fechaPrevista
     1    9474       0402       2020-05-01 00:00:00.000
     2    9474       0808       2020-01-01 00:00:00.000
     3    9474       0101       2019-12-19 00:00:00.000
     4    9473       2001       2018-02-08 00:00:00.000
     5    9473       1901       2019-05-23 00:00:00.000
     6    9473       1901       2017-08-17 00:00:00.000
     7    9472       0808       2020-11-11 00:00:00.000
     8    9472       0101       2019-01-01 00:00:00.000

我需要遍历表 Equipo 中的每个设备并为每个设备执行以下步骤:

  1. 在设备数据校准中,按 magnitudId 分组,并为每个 magnitudId 获取最近的 fechaPrevista(注意同一设备可能重复幅度)。
  2. 一旦我有了每个幅度 (magnitudId) 的最新日期和时间 (fechaPrevista),我想获得最旧的 fechaPrevista

所以我执行下面的 LINQ 表达式:

LINQ 表达式

Dim eq = db.Equipo
For Each equipo As Equipo In eq
   Dim fechaPrevista As DateTime? =
    (From c In equipo.CalibracionVerificacion
     Join c2 In (From c3 In equipo.CalibracionVerificacion
                 Where c3.equipoId = equipo.equipoId AndAlso Not (String.IsNullOrWhiteSpace(c3.magnitudId))
                 Group c3 By c3.magnitudId Into cgroup = Group
                 Select New With
                 {
                    Key .MagnitudID = magnitudId,
                    Key .MaxDate = cgroup.Max(Function(x) x.fechaPrevista)
                 }
                 ) On New With {.JoinProperty1 = c.magnitudId, .JoinProperty2 = c.fechaPrevista} Equals
                      New With {.JoinProperty1 = c2.MagnitudID, .JoinProperty2 = c2.MaxDate}
                 Where c.equipoId = equipo.equipoId
                 Select c).Min(Function(d) d.fechaPrevista))

    // Do something with fechaPrevista

Next

我通过直接指向数据库检查了 LINQPad 5 中的相同 LINQ 表达式,它工作正常。

例如,考虑到上表,对于equipoId = 9474,我想获得最早的日期和时间,即 2019-12-19 00:00:00.000,但由于 fechaPrevista,我什么也没得到。

由于我无法调试上述 LINQ 表达式,因此我将查询分解为多个部分。我一直在调试上面的 LINQ 表达式,分为两部分:内部和外部 Linq 表达式。对于下面的内部 Linq 表达式:(假设在此示例中,equipo.equipoId = 9474):

Dim c23 = From c3 In equipo.CalibracionVerificacion
          Where c3.equipoId = equipo.equipoId AndAlso Not (String.IsNullOrWhiteSpace(c3.magnitudId))
          Group c3 By c3.magnitudId Into cgroup = Group
          Select New With
          {
              Key .MagnitudID = magnitudId,
              Key .MaxDate = cgroup.Max(Function(x) x.fechaPrevista)
          }

...我得到了正确的结果。它正在工作并返回以下结果:

在此处输入图像描述

所以内部 LINQ 表达式运行良好。问题在于外部 LINQ 表达式,自联接失败,然后返回 Nothing 作为结果。我不懂为什么。有任何想法吗?

基本上,翻译成 SQL Server 的 LINQ 表达式是(例如,为了简化,一个equipoId 是):

-- Region Parameters
DECLARE @p0 Int = 9474
DECLARE @p1 Int = 9474
-- EndRegion
SELECT MIN([t0].[fechaPrevista]) AS [value]
FROM [eq].[CalibracionVerificacion] AS [t0]
INNER JOIN (
    SELECT MAX([t1].[fechaPrevista]) AS [value], [t1].[magnitudId]
    FROM [eq].[CalibracionVerificacion] AS [t1]
    WHERE [t1].[equipoId] = @p0
    GROUP BY [t1].[magnitudId]
    ) AS [t2] ON ([t0].[magnitudId] = [t2].[magnitudId]) AND ([t0].[fechaPrevista] = [t2].[value])
WHERE [t0].[equipoId] = @p1

标签: vb.netentity-frameworklinqedmx

解决方案


使用 LINQ,以声明方式(即,根据期望的结果)进行思考比以命令方式(即,控制流)进行思考更有帮助。据我所知,最终您希望迭代具有以下属性/字段的结果集:

  • 等价
  • 幅度标识
  • 第一次 fechaPrevista
  • 最后 fechaPrevista

我可能误会你了。从您的描述中,不清楚您是否想要每组的最后一个 fechaPrevista 与所有实体/记录的最后一个。此外,我在这里假设您希望跳过 Equipo 中没有 CalibracionVerificacion 中没有子项的任何行。如果我在这里的假设是准确的,那么这应该会让你得到你所追求的:

Dim data = db.CalibracionVerificacion

    Dim qry = (From item in data group by grp = New With {Key item.equipoId, Key item.magnitudId} into finalGrp = Group
        Select New With
            {
                .equipoId = grp.equipoId,
                .magnitudId = grp.magnitudId,
                .firstFechaPrevista = finalGrp.Min(function(g) g.fechaPrevista),
                .lastFechaPrevista = finalGrp.Max(function(g) g.fechaPrevista)
                }).ToList


                For each item in qry
                    'do something               
                next

推荐阅读