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

如何在LINQ中使用类似SQL EXISTS的功能实现指定账户余额计算

LINQ实现EXISTS逻辑及指定SQL转LINQ方案

问题场景

现有两段LINQ代码,第一段用于筛选符合条件的特定账户:

var _query = _dbContext.CashVoucherDetails
             .Where(x => x.CreationDate.Date >= From.Date && x.CreationDate.Date <= To.Date && (x.Type == Common.TransactionType.CPV || x.Type == Common.TransactionType.BPV) && x.CompanyCode == BranchCode && x.DebitAmount > 0)
             .GroupBy(v => new { v.AccountCode})
             .Select(g => new
              {
                 AccountCode = g.Key.AccountCode,
              });

var balances = _dbContext.CashVoucherDetails
               .Where(x => x.CreationDate.Date <= To.Date && x.CompanyCode == BranchCode)
             //.Exist(_query.Account) (I want only account which exist in upper query)
               .GroupBy(v => new { v.AccountCode})
               .Select(g => new
               {
                   AccountCode = g.Key.AccountCode,
                   Balance = g.Sum(x => x.DebitAmount - x.CreditAmount),
                });

需求是在第二段查询中用类似SQL EXISTS 的功能,只计算第一段查询中存在的账户的余额。同时需要将以下SQL查询转换为LINQ实现:

SELECT `c`.`AccountCode`, `c`.`CompanyCode` AS `LocationCode`, COALESCE(SUM(`c`.`DebitAmount` - `c`.`CreditAmount`), 0) AS `Balance`
    FROM `CashVoucherDetails` AS `c`
    WHERE (CONVERT(`c`.`CreationDate`, date) <= '2022-12-20') AND (`c`.`CompanyCode` = '002') and `c`.`AccountCode` IN 
    (
        SELECT `c`.`AccountCode`
        FROM `CashVoucherDetails` AS `c`
        WHERE ((((CONVERT(`c`.`CreationDate`, date) >= '2022-12-20') AND (CONVERT(`c`.`CreationDate`, date) <= '2022-12-20')) AND `c`.`Type`     IN ('CPV', 'BPV')) AND (`c`.`CompanyCode` = '002')) AND (`c`.`DebitAmount` > 0)
        GROUP BY `c`.`AccountCode` 
    )
    GROUP BY `c`.`AccountCode`, `c`.`CompanyCode`;

一、LINQ中实现类似EXISTS的逻辑

在LINQ里,用Any()方法即可实现SQL的EXISTS效果。修改第二段查询的Where条件,加入对第一段查询的存在性判断:

var balances = _dbContext.CashVoucherDetails
               .Where(x => x.CreationDate.Date <= To.Date && x.CompanyCode == BranchCode 
                           // 用Any实现EXISTS逻辑,判断当前账户是否在_query中存在
                           && _query.Any(q => q.AccountCode == x.AccountCode))
               .GroupBy(v => new { v.AccountCode})
               .Select(g => new
               {
                   AccountCode = g.Key.AccountCode,
                   Balance = g.Sum(x => x.DebitAmount - x.CreditAmount),
                });

也可以先提取第一段查询的账户Code集合,用Contains实现类似IN的效果(EF会自动转换为对应的SQL,性能和Any差异不大):

// 先提取符合条件的账户Code集合
var validAccountCodes = _query.Select(q => q.AccountCode).ToList();

var balances = _dbContext.CashVoucherDetails
               .Where(x => x.CreationDate.Date <= To.Date && x.CompanyCode == BranchCode 
                           && validAccountCodes.Contains(x.AccountCode))
               .GroupBy(v => new { v.AccountCode})
               .Select(g => new
               {
                   AccountCode = g.Key.AccountCode,
                   Balance = g.Sum(x => x.DebitAmount - x.CreditAmount),
                });

二、对应SQL的LINQ实现

要把给出的SQL转成LINQ,核心是实现子查询过滤,同时处理COALESCE(LINQ中用??结合Sum(),或DefaultIfEmpty().Sum()):

// 替换为实际业务中的变量
var targetDate = new DateTime(2022, 12, 20);
var companyCode = "002";

// 子查询:获取符合条件的账户Code
var subQuery = _dbContext.CashVoucherDetails
    .Where(c => c.CreationDate.Date >= targetDate.Date 
                && c.CreationDate.Date <= targetDate.Date 
                && (c.Type == "CPV" || c.Type == "BPV") // 若为枚举类型,改用Common.TransactionType.CPV等
                && c.CompanyCode == companyCode 
                && c.DebitAmount > 0)
    .GroupBy(c => c.AccountCode)
    .Select(g => g.Key);

// 主查询:计算符合条件账户的余额
var result = _dbContext.CashVoucherDetails
    .Where(c => c.CreationDate.Date <= targetDate.Date 
                && c.CompanyCode == companyCode 
                && subQuery.Any(s => s == c.AccountCode)) // 也可改用subQuery.Contains(c.AccountCode)
    .GroupBy(c => new { c.AccountCode, c.CompanyCode })
    .Select(g => new
    {
        AccountCode = g.Key.AccountCode,
        LocationCode = g.Key.CompanyCode,
        // 用??处理SUM为null的情况,等效于SQL的COALESCE
        Balance = g.Sum(c => c.DebitAmount - c.CreditAmount) ?? 0
    });

如果EF版本不支持Sum()直接返回null,可改用g.Select(c => c.DebitAmount - c.CreditAmount).DefaultIfEmpty(0).Sum()实现COALESCE的效果。

内容的提问来源于stack exchange,提问作者Åfsħąl Ãtħąr

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 17:10:20