【问题标题】:c# method chain vs linq queryc# 方法链 vs linq 查询
【发布时间】:2025-12-07 19:45:02
【问题描述】:

我在方法链中写了一个查询:

var query = finnEntities.FINN_TRANSACTION_VIEW.Where(
        x => x.CREDIT_ID == model.CodeId 
        || x.DEBTOR_ID == model.CodeId 
        && (x.TRANSACTION_DATE>= model.DateTimeFrom.Date 
            && x.TRANSACTION_DATE <= model.DateTimeTo.Date) 
        && x.CURRENCY_TYPE_ID == model.CurrencyId);

我使用 linq 表达式编写了相同的查询:

var queryTransaction = 
    from t in finnEntities.FINN_TRANSACTION_VIEW
    where (t.CREDIT_ID == model.CodeId 
        || t.DEBTOR_ID == model.CodeId) 
        && (t.TRANSACTION_DATE >= model.DateTimeFrom 
            && t.TRANSACTION_DATE <= model.DateTimeTo) 
        && t.CURRENCY_TYPE_ID == model.CurrencyId
    select new { t };

但他们有不同的输出,第二个返回正确的结果

【问题讨论】:

  • 您没有编写相同的查询 - 以及 where 子句不同,您的查询表达式使用匿名类型的投影,没有明显的原因。
  • 还有什么问题?

标签: c# linq entity-framework method-chaining


【解决方案1】:

如果您查看这两个查询,您会发现您有

  1. () 在第二个查询中围绕 t.CREDIT_ID == model.CodeId || t.DEBTOR_ID == model.CodeId 而您在第一个查询中没有它们。这会改变 where 子句中的操作顺序。

  2. 在第一个中添加了.Date,它会截断到当天,但不会截断到第二个。

假设第二个查询确实返回了正确的结果,您可以将第一个查询更改为:

var query = finnEntities.FINN_TRANSACTION_VIEW.Where(x =>
    (x.CREDIT_ID == model.CodeId || x.DEBTOR_ID == model.CodeId)
    && x.TRANSACTION_DATE>= model.DateTimeFrom
    && x.TRANSACTION_DATE <= model.DateTimeTo
    && x.CURRENCY_TYPE_ID == model.CurrencyId);

在上面,我还在查询的 anded 部分周围删除了多余的 ()

【讨论】:

  • 你给出正确的我忘了把大括号放在日期比较周围。
【解决方案2】:

你的括号是不同的。只需比较一下您是如何编写条件的,您应该会注意到括号和日期差异。

x.CREDIT_ID == model.CodeId || x.DEBTOR_ID == model.CodeId && (x.TRANSACTION_DATE>= model.DateTimeFrom.Date && x.TRANSACTION_DATE <= model.DateTimeTo.Date) && x.CURRENCY_TYPE_ID == model.CurrencyId


(t.CREDIT_ID == model.CodeId || t.DEBTOR_ID == model.CodeId) && (t.TRANSACTION_DATE >= model.DateTimeFrom && t.TRANSACTION_DATE <= model.DateTimeTo) && t.CURRENCY_TYPE_ID == model.CurrencyId

将更复杂的条件放入这样的函数中也是一个好主意(为了便于阅读):

bool _iHaveAMeaningfulName(Model model, WhatEver t)
{
    return (t.CREDIT_ID == model.CodeId || t.DEBTOR_ID == model.CodeId) && 
           (t.TRANSACTION_DATE >= model.DateTimeFrom && t.TRANSACTION_DATE <= model.DateTimeTo) && 
            t.CURRENCY_TYPE_ID == model.CurrencyId
}

然后您可以更轻松地重用它,并更好地将 Linq-Queries 与方法链进行比较:

// Method-Chain
finnEntities.FINN_TRANSACTION_VIEW.Where(t => _iHaveAMeaningfulName(model,t));

// query
from f in finnEntities.FINN_TRANSACTION_VIEW
where _iHaveAMeaningfulName(f,model)
select new { f }; // this returns an annonymous type

您还应该注意到,您的查询返回了一个匿名类型,因为您写道:

select new { f };

为了等效于方法链,您需要删除新的 { }

select f;

【讨论】:

  • 实际上在这种情况下括号不会影响逻辑。正如 Habib 指出的那样,OP 正在以不同的方式比较日期。
  • 我不能同意 'a or b and c' 等同于 '(a or b) and c'