【问题标题】:LINQ Join inside Join, how to?LINQ Join里面的Join,怎么做?
【发布时间】:2011-02-24 19:44:31
【问题描述】:

我是 LINQ 的新手。我正在使用 LINQ to Objects(我认为)并且数据的设置方式我无法直接获取我需要的数据。 这是我需要做的一般结构:

FROM Project
    LEFT OUTER JOIN TechnologySectors
    LEFT OUTER JOIN SelectedAgencies
    LEFT OUTER JOIN ProjectStatus
        JOIN Process

我需要来自 Process 的单条数据。
到目前为止,我已经弄清楚如何使用DefaultIfEmpty() 使用 LINQ 进行 LEFT OUTER JOIN,但我无法弄清楚如何使用 ProjectStatus 让 Process 加入。
到目前为止我有这个(ps是ProjectStatus):

join ec in this._Process.GetProcessList() on ps.ProcessID equals ec.ProcessID into psec

但这给了我一个关于“ps不在等号左侧范围内”的错误。

编辑
为了参考起见,我包含的“加入”并不是整个陈述。 “ProjectStatus”(ps)加入了“Project”(pr),我也需要加入“Process”(ec)。
ec 和 pr 没有直接关系,所以必须通过 ps 加入。 翻转“on”语句并不能解决问题。

编辑 2
完整的 LINQ 查询:

from pr in this._projectRepo.GetAllProjects()
join tr in this._techRepo.GetTechnologySectors() on pr.TechnologySectorID equals tr.TechnologySectorID into prtr
join ev in this._ecEnvRepo.GetAllSelectedAgencies() on pr.ID equals ev.ID into prev
join ps in this._ecProjectStatRepo.GetAllECProjectStatus() on pr.ID equals ps.ID into prps
***THIS LINE***join ec in this._ecProcessRepo.GetProcessList() on ps.ProcessID equals ec.ProcessID into psec
from tr in prtr.DefaultIfEmpty()
from ev in prev.DefaultIfEmpty()
from ps in prps.DefaultIfEmpty()
from ec in psec.DefaultIfEmpty()

那行不通。
我也试过去掉那条线并使用它:

from ec in this._ecProcessRepo.GetProcessList() where (ec.ProcessID == ps.ProcessID)

我已经尝试使用这个来代替 ps 和 ec 行:

from ps in this._ecProjectStatRepo.GetAllECProjectStatus() where (ps.ID == pr.ID)
join ec in this._ecProcessRepo.GetProcessList() on ps.ProcessID equals ec.ProcessID into psec
from ec in psec.DefaultIfEmpty()

【问题讨论】:

    标签: linq join linq-to-objects left-join


    【解决方案1】:

    您只需要翻转on 语句

    join ec in this._Process.GetProcessList() on ec.ProcessID equals ps.ProcessID into psec

    关于多个连接,您应该能够将它们链接起来

    【讨论】:

    • 您能否提供更多的 Linq 查询,因为我们可能缺少某些内容。
    • 那是因为有错别字,已修复
    【解决方案2】:

    你只需要交换ecps

    ec in this._Process.GetProcessList() on 
        ps.ProcessID equals ec.ProcessID into psec
    

    要进行左连接,您需要执行以下操作

    ec in this._Process.GetProcessList() on 
        ps.ProcessID equals ec.ProcessID into nullablePsec
    from ec in nullablePsec.DefaultIfEmpty()
    

    有多种方法可以命名对象,但我通常会发现我编写连接以进入带有可为空前缀的对象名称,然后使用下一行 from ec in nullablePsec.DefaultIfEmpty() 再次为其赋予相同的名称

    编辑:看到完整的 linq 查询后,您需要像这样加入

    ec in this._Process.GetProcessList() on 
        prps.ProcessID equals ec.ProcessID into psec
    

    请注意这里的连接是在 prps 变量名称上,因为您正在选择它上面一行中的 prps

    join ps in this._ecProjectStatRepo.GetAllECProjectStatus() on pr.ID equals ps.ID into prps
    

    into prps 已将您将在连接查询中使用的变量名称更改为进程列表。

    编辑 2 如果你把语句写成如下这样可能会更好一些

    from pr in this._projectRepo.GetAllProjects()
    join tr in this._techRepo.GetTechnologySectors() on pr.TechnologySectorID equals tr.TechnologySectorID into prtr
    from tr in prtr.DefaultIfEmpty()
    join ev in this._ecEnvRepo.GetAllSelectedAgencies() on pr.ID equals ev.ID into prev
    from ev in prev.DefaultIfEmpty()
    join ps in this._ecProjectStatRepo.GetAllECProjectStatus() on pr.ID equals ps.ID into prps
    from ps in prps.DefaultIfEmpty()
    join ec in this._ecProcessRepo.GetProcessList() on ps.ProcessID equals ec.ProcessID into psec
    from ec in psec.DefaultIfEmpty()
    

    【讨论】:

    • 你说的第一种方法的问题是prps没有ProcessID。如果我尝试第二种方法,我会在运行代码时遇到很多对象引用错误。
    【解决方案3】:

    当您进行组连接时,内部序列中的变量会超出范围,您将无法再访问各个元素。如果您想要访问或不首先加入群组,则需要将关联的DefaultIfEmpty() 向上移动。

    var query = from pr in this._projectRepo.GetAllProjects()
                join tr in this._techRepo.GetTechnologySectors()
                    on pr.TechnologySectorID equals tr.TechnologySectorID
                    into prtr
                join ev in this._ecEnvRepo.GetAllSelectedAgencies()
                    on pr.ID equals ev.ID
                    into prev
                join ps in this._ecProjectStatRepo.GetAllECProjectStatus()
                    on pr.ID equals ps.ID
                     into prps
                from ps in prps.DefaultIfEmpty()
                // you need to resolve `ps == null` issues here
                let key = ps == null ? -1 : ps.ProcessID
                join ec in this._ecProcessRepo.GetProcessList()
                    on key equals ec.ProcessID
                    into psec
                from tr in prtr.DefaultIfEmpty()
                from ev in prev.DefaultIfEmpty()
                from ec in psec.DefaultIfEmpty()
                // ...
    

    【讨论】:

    • 使用此方法最终会明显缺少 OUTER JOIN,因为我的记录从 245 变为 4,因为只有 4 条记录具有分配给它们的 ProcessID,这就是我开始尝试这样做的原因整个时间。
    • @Pselus:在这种情况下,请使用我提到的另一种方法。我的示例使用了我这边需要较少猜测的方法。如果您需要外部连接,请像我说的那样移动DefaultIfEmpty() 调用。但是当它产生null 值时,您必须解决这些情况。
    猜你喜欢
    • 2021-04-28
    • 2016-04-06
    • 2016-07-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-27
    • 1970-01-01
    • 2021-02-20
    相关资源
    最近更新 更多