在 C# 代码中的 DB 中的 Linq 查询中包含空单元格

Posted

技术标签:

【中文标题】在 C# 代码中的 DB 中的 Linq 查询中包含空单元格【英文标题】:Include null cells in Linq query from DB in C# code 【发布时间】:2021-11-23 03:03:04 【问题描述】:

我只想知道是否仍然可以从 linq 查询中检索空单元格,因为即使单元格为“空”,我也需要这些行。

上下文是我有一个基于客户合同的版本控制,我更新他们的应用程序并使用最新版本构建和更新日期更新数据库。此报告返回所有合同及其最新更新构建和每个合同的更新日期。

我在 SQL 中有这个查询,用于生成报告:

SELECT c.contrato, b.build, MAX(p.data_atualizacao) AS [data_atualizacao] 
FROM
(
    SELECT id_contrato, MAX(id_build_verus) AS id_build_verus FROM tbl_controle_atualizacao_contrato
    GROUP BY id_contrato
) d
JOIN tbl_controle_atualizacao_contrato P ON p.id_contrato = d.id_contrato AND p.id_build_verus = d.id_build_verus
RIGHT JOIN tbl_contrato c WITH(NOLOCK) ON p.id_contrato = c.id_contrato
LEFT JOIN tbl_build_verus b WITH(NOLOCK) ON p.id_build_verus = b.id_build_verus
WHERE c.contrato <> 0 AND c.id_empresa = 1 AND c.ativo = 1
GROUP BY c.contrato, b.build

输出是这样的:

然后在我的代码中,我设置了一个 linq 表达式,它为我返回一个具有相同结果的查询:

var listaTotalContratos = db.tbl_controle_atualizacao_contrato.Include(i => i.tbl_contrato).OrderByDescending(d => d.data_atualizacao).ThenByDescending(b => b.tbl_build_verus.build)
                .Where(c => c.tbl_contrato.contrato != 0 && c.tbl_contrato.ativo == true && c.tbl_contrato.id_empresa == 1)
                .Select(r => new
                
                    contrato = r.tbl_contrato.contrato.ToString(),
                    UF = r.tbl_contrato.tbl_cliente.tbl_pessoa.tbl_endereco.FirstOrDefault().uf,
                    build = r.tbl_build_verus.build,
                    data_atualizacao = r.tbl_contrato.tbl_controle_atualizacao_contrato.Max(x => x.data_atualizacao)
                ).GroupBy(c => c.contrato).Select(s => new  contrato = s.Key, listaItens = s.ToList() ).ToList();

我进行了自定义选择以从单元格中获取值,因为我得到了重复的结果。

linq 代码有效,但我认为它忽略了带有空单元格的行。

谢谢!

【问题讨论】:

在 SQL 查询中,您在 tbl_build_verus 上执行 LEFT JOIN,而 linq 查询中不存在,这就是它忽略空字段的原因。您需要将确切的查询转换为 linq 查询,其中包含 LEFT JOIN,否则它将执行正常的 JOIN。您可以使用一些适配器来查看 linq 正在生成什么 SQL 查询以及您的错误在哪里。 【参考方案1】:

在 SQL 查询中,您在 tbl_build_verus 上执行 LEFT JOIN,而 linq 查询中不存在,这就是它忽略空字段的原因。您需要将确切的查询转换为 linq 查询,其中包含 LEFT JOIN,否则它将执行正常的 JOIN。

你的结果应该是这样的:

var query = 
    from d in tbl_controle_atualizacao_contrato
    join p in tbl_controle_atualizacao_contrato 
        on p.id_contrato = d.id_contrato 
        AND p.id_build_verus = d.id_build_verus
    join c in tbl_contrato 
        on p.id_contrato = c.id_contrato
    left join b in tbl_build_verus 
        ON p.id_build_verus = b.id_build_verus
        select new 
        
            c.contrato, 
            b.build, 
            data_atualizacao = MAX(p.data_atualizacao) 
        
    where c.contrato <> 0 AND c.id_empresa = 1 AND c.ativo = 1
    GROUP BY c.contrato, b.build;

我建议在您的开发环境中使用某种类型的拦截器/分析器,这样您就可以实时查看 EF 正在执行的查询。见this

拦截器示例:

public class CommandInterceptor : DbCommandInterceptor
    
        public override InterceptionResult DataReaderDisposing(DbCommand command, DataReaderDisposingEventData eventData, InterceptionResult result)
        
            Debug.WriteLine(command.CommandText);
            return base.DataReaderDisposing(command, eventData, result);
        

        public override int NonQueryExecuted(DbCommand command, CommandExecutedEventData eventData, int result)
        
            Debug.WriteLine(command.CommandText);
            return base.NonQueryExecuted(command, eventData, result);
        

        public override DbDataReader ReaderExecuted(DbCommand command, CommandExecutedEventData eventData, DbDataReader result)
        
            Debug.WriteLine(command.CommandText);
            return base.ReaderExecuted(command, eventData, result);
        

        public override object ScalarExecuted(DbCommand command, CommandExecutedEventData eventData, object result)
        
            Debug.WriteLine(command.CommandText);
            return base.ScalarExecuted(command, eventData, result);
        
    

拦截器注册

services.AddDbContext<Context>(contextOptions =>
            
                contextOptions                    
                    .AddInterceptors(new CommandInterceptor())                
            );

【讨论】:

很好的解释!我没有考虑连接问题,因为我认为导航正在通过 linq 表达式进行所有连接......我将尝试这种方法并检查这个拦截器机制。非常感谢朋友!

以上是关于在 C# 代码中的 DB 中的 Linq 查询中包含空单元格的主要内容,如果未能解决你的问题,请参考以下文章

C#中的LINQ

linq中的算术运算使用实体框架mvc C#

C# 之 LINQ简析

LINQ to SQL 可以查询 XML 字段 DB-serverside 吗?

如何通过循环 db [C# MVC & LINQ] 中的 3 个表来映射数据以对应表头

C# 中的 LINQ to SQL 查询