You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用LINQ实现INNER JOIN及特定WHERE条件的查询

问题描述

现有两个数据库表:

ReconFinalCost (Id, LeaseDocNumber, SnapshotId)  
ReconSnapshot (Id, FiscalYear, FiscalQuarter)

其中ReconFinalCost.SnapshotId是ReconSnapshot.Id的外键。

在C#代码中,我有一个List<ReconFinalCost> leaselist,需要编写LINQ语句实现以下逻辑:将ReconFinalCost与ReconSnapshot按ReconFinalCost.SnapshotId == ReconSnapshot.Id内连接,保留leaselist中所有满足不存在其他LeaseDocNumber相同的ReconFinalCost条目,且该条目对应的ReconSnapshot财年相同但财季更大的数据。

对应的SQL查询如下:

select * from "ReconFinalCost"
inner join "ReconSnapshot" on "ReconFinalCost"."SnapshotId" = "ReconSnapshot"."Id"
where NOT EXISTS (
    SELECT 1 FROM "ReconFinalCost" B
    inner join "ReconSnapshot" RS2 on RS2."Id" = B."SnapshotId"
    where  "ReconFinalCost"."LeaseDocNumber" = B."LeaseDocNumber" and             
           ( RS2."FiscalYear" = "ReconSnapshot"."FiscalYear" and 
             RS2."FiscalQuarter" > "ReconSnapshot"."FiscalQuarter" )
    )

当前我的代码实现:

List<ReconFinalCost> leaselist;
List<ReconFinalCost> originalLeaseList = leaselist;
leaselist = leaselist
    .Where(x => !originalLeaseList.Any(
        y => y.LeaseDocNumber == x.LeaseDocNumber &&
            getIdsOfFutureQuarterSnapshots(x.SnapshotId).Any(
                 futureSnapshotId => futureSnapshotId == y.SnapshotId) ) )
    .OrderBy(x => x.LeaseDocNumber).ToList();
...

private List<long> getIdsOfFutureQuarterSnapshots(long? snapshotId)
{
     // 此函数返回与给定snapshotId同财年但财季更大的ReconSnapshot的Id列表
     ReconSnapshot givenSnapshot = repository.GetReconSnapshotByID( (int)snapshotId );
     return _context.ReconSnapshots.Where(r =>   r.FiscalYear == givenSnapshot.FiscalYear && 
            r.FiscalQuarter > givenSnapshot.FiscalQuarter ).Select(r => r.Id).ToList();
}

请问如何编写LINQ语法,直接实现ReconFinalCost与ReconSnapshot的内连接,并指定「相同财年但更大财季」的WHERE条件,替代当前调用单独函数的方式?


解决方案

场景1:直接通过EF Core查询数据库(性能更优)

如果leaselist是从数据库查询而来,建议直接用IQueryable编写查询,LINQ会被翻译成SQL执行,避免内存中处理大量数据:

// 假设_context是你的DbContext实例
var result = _context.ReconFinalCost
    .Join(_context.ReconSnapshot,
          cost => cost.SnapshotId,
          snapshot => snapshot.Id,
          (cost, snapshot) => new { cost, snapshot })
    .Where(joined => !_context.ReconFinalCost
        .Join(_context.ReconSnapshot,
              b => b.SnapshotId,
              rs2 => rs2.Id,
              (b, rs2) => new { b, rs2 })
        .Any(subJoined => subJoined.b.LeaseDocNumber == joined.cost.LeaseDocNumber &&
                          subJoined.rs2.FiscalYear == joined.snapshot.FiscalYear &&
                          subJoined.rs2.FiscalQuarter > joined.snapshot.FiscalQuarter))
    .Select(joined => joined.cost)
    .OrderBy(cost => cost.LeaseDocNumber)
    .ToList();

这段代码完全对应给出的SQL逻辑,通过两次Join实现NOT EXISTS的过滤条件,最终返回符合要求的ReconFinalCost列表。

场景2:处理内存中的List

如果leaselist已经是内存中的集合,先把关联的ReconSnapshot数据加载到内存,再进行处理:

// 先批量获取所有相关的ReconSnapshot数据,避免多次查询数据库
var snapshotIds = leaselist.Where(c => c.SnapshotId.HasValue).Select(c => c.SnapshotId.Value).Distinct();
var snapshotDict = _context.ReconSnapshots
    .Where(s => snapshotIds.Contains(s.Id))
    .ToDictionary(s => s.Id);

var result = leaselist
    .Where(c => c.SnapshotId.HasValue)
    .Join(snapshotDict,
          cost => cost.SnapshotId.Value,
          snapshotKv => snapshotKv.Key,
          (cost, snapshotKv) => new { cost, snapshot = snapshotKv.Value })
    .Where(joined => !leaselist
        .Where(b => b.SnapshotId.HasValue)
        .Join(snapshotDict,
              b => b.SnapshotId.Value,
              rs2Kv => rs2Kv.Key,
              (b, rs2Kv) => new { b, rs2 = rs2Kv.Value })
        .Any(subJoined => subJoined.b.LeaseDocNumber == joined.cost.LeaseDocNumber &&
                          subJoined.rs2.FiscalYear == joined.snapshot.FiscalYear &&
                          subJoined.rs2.FiscalQuarter > joined.snapshot.FiscalQuarter))
    .Select(joined => joined.cost)
    .OrderBy(cost => cost.LeaseDocNumber)
    .ToList();

这里先将需要的ReconSnapshot数据存入字典,避免重复查询数据库,之后在内存中完成Join和条件过滤,逻辑与SQL完全匹配。

内容的提问来源于stack exchange,提问作者user3034243

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 04:25:39