在 EF LINQ 查询 if 子句中引发空引用异常

Posted

技术标签:

【中文标题】在 EF LINQ 查询 if 子句中引发空引用异常【英文标题】:Null reference exception being thrown in EF LINQ query if-clause 【发布时间】:2018-06-17 20:07:21 【问题描述】:

我找不到确切的词来解释发生了什么,所以如果这是一个重复的问题,我很抱歉。

我尝试在 LINQ 查询中执行一个非常简单的 AND 条件 if 子句,以检查对象是否为空,然后验证其属性是否等于我想要比较的列。

代码:

public IEnumerable<Plan> GetPlans(Plan plan)
    
        return _context.Plans.Where(e =>
            e.Situation == plan.Situation &&
            e.Notes.Contains(plan.Notes) &&
            (plan.Excercise != null && plan.Exercise.Year > 0 ? e.Exercise.Year == plan.Exercise.Year: true)).ToList();
    

我之前已经在 .NET 4.5 中进行过十几次此类检查,没有出现任何问题。

但是现在,在我正在处理的第一个 .NET Core 2.0 项目中,我遇到了以下错误:

An exception was thrown while attempting to evaluate a LINQ query parameter expression. To show additional information call EnableSensitiveDataLogging() when overriding DbContext.OnConfiguring.

内部异常更清楚:NULL REFERENCE EXCEPTION

经过一些测试,我发现错误发生在 plan.Exercise 为空时,即使我尝试通过首先检查它是否为空来避免异常。

如果我尝试直接在即时窗口中进行相同的检查,它会返回“false”,应该是这样。

我在这里遗漏了什么吗?这可能是一个EF错误?例如,为什么这在 .NET 4.5 中有效,而在 .NET Core 2.0 中无效?

提前致谢。

更新

Ivan 的解决方案成功了:

重写? : 等价的构造||

plan.Excercise == null || plan.Exercise.Year <= 0 || e.Excercise.Year == plan.Exercise.Year

【问题讨论】:

查看null condition operator 让我们澄清一下条款。您是在询问 EF Core 2.0 吗?如果是,NET 4.5 和 NET Core 应该是无关的(EF Core 2.0 不支持 NET 4.5)。请相应地更新帖子和标签。 @thiagoprzy 你没抓住重点。 EF Core 及其版本是最重要的知识,而不是 NET (Core)。无论如何,这是 EF Core 错误(现在无法在他们的问题跟踪器中找到它)。用等效的 || 重写 ? : 结构,例如plan.Excercise == null || plan.Exercise.Year &lt;= 0 || e.Excercise.Year == plan.Exercise.Year @IvanStoev 好的,我明白了。当问题应该代表 EF 时,我正在谈论 .NET。对于那个很抱歉。您的解决方案完成了这项工作。 @Gert 他们正在尝试预评估和消除 const 参数表达式(对 EF6 的改进,我试图使用表达式后处理器 here 进行改进)。他们确实为二进制表达式正确短路,但未能为条件运算符这样做。 【参考方案1】:

听起来这可能是 EF Core 中的一个错误(但我不确定)。

如果不满足plan 的基本要求,您可能会尝试的一件事是快速失败,更重要的是,不要使用三元运算符,而是使用传统的比较运算符和括号:

public IEnumerable<Plan> GetPlans(Plan plan)

    if (plan == null) return new List<Plan>();

    return _context.Plans
        .Where(e =>
            e.Situation == plan.Situation &&
            e.Notes.Contains(plan.Notes) &&
            (plan.Exercise == null || 
            plan.Exercise.Year <= 0 || 
            e.Excercise.Year == plan.Exercise.Year))
        .ToList();

【讨论】:

【参考方案2】:

为避免此问题,请确保您不是在评估空对象。

var exercice = await _repositoryExercice.FirstOrDefaultAsync(i => i.IsCurrent);
var depenses = _repositoryDepense.GetAll()
                .Where( e => e.ExerciceId.Equals(exercice.Id))
                .WhereIf(AbpSession.TenantId.HasValue, m => m.TenantId.Value.Equals(AbpSession.TenantId.Value))
                .ToList();

问题是由这一行 .Where( e =&gt; e.ExerciceId.Equals(exercice.Id)) 引起的,因为变量 exercice 为空。

最佳实践,我用这个替换了那行:

...
.WhereIf(exercice != null, e => e.ExerciceId.Equals(exercice.Id))
...

【讨论】:

【参考方案3】:

如何将你的代码简化成类似的东西

public IEnumerable<Plan> GetPlans(int year)

    return _context.Plans
        .Where(e => e.Excercise.Year == year)
        .ToList();

【讨论】:

Where 子句中有更多条件,我只是将它们删除以不让代码“混乱”。我将编辑问题以使其更明显。

以上是关于在 EF LINQ 查询 if 子句中引发空引用异常的主要内容,如果未能解决你的问题,请参考以下文章

LINQ 实体框架查询在 EF Core 中不起作用,引发异常

EF 6.x,LINQ-to-SQL和原始SQL子句

具有多个条件和子句的C#EF Linq语法查询

关于为啥这个 linq ef 核心查询不会执行的建议

LINQ/LinqPad:相同的查询不同的结果

linq 在查询表达式中处理异常