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

EF Core子查询报错:Nullable object must have a value问题求助

EF Core 查询中因ratingDef为null导致子查询报错的解决问题

我在Entity Framework Core中编写了如下方法(为简化仅保留关键属性):

public async Task<TemplateDetailsDto?> SearchDetailsAsync(CancellationToken cancellationToken, Guid templateKey)
{
    var search = await (from template in context.Set<Template>()
                        join ratingDef in context.Set<RangeDefinition>() on template.FinalRatingRangeId equals ratingDef.Id into ratingGroup
                        from ratingDef in ratingGroup.DefaultIfEmpty()
                        where template.Key == templateKey
                        select new TemplateDetailsDto
                        {
                            Key = template.Key,
                            FinalRatingRange = ratingDef == null ? null : (new TemplateRangeDetailsDto
                            {
                                Legend = ratingDef.Legend,
                                RangeTypeId = (QuestionsTypeDto)ratingDef.RangeTypeId,
                                RangesValues = context.Set<RangeValue>()
                                        .Where(rangValue => rangValue.RangeDefinitionId == ratingDef.Id)
                                        .Select(rangValue => new TemplateRangeDetailsDto
                                        {
                                            Id = rangValue.Id,
                                            Value = rangValue.Value,
                                        })
                                        .ToList(),
                            }),
                        })
                        .AsNoTracking()
                        .SingleOrDefaultAsync(cancellationToken);

    return search;
}

运行时抛出如下异常:

System.InvalidOperationException : Nullable object must have a value

错误发生在以下代码行:

RangesValues = context.Set<RangeValue>()
    .Where(rangValue => rangValue.RangeDefinitionId == ratingDef.Id)
    .Select(rangValue => new TemplateRangeDetailsDto
    {
        Id = rangValue.Id,
        Value = rangValue.Value,
    })
    .ToList(),

注释掉该部分代码后程序正常运行。问题在于ratingDef可能为null,导致子查询报错,请问该如何解决?


更新1:
我使用内存数据库进行测试,测试代码如下:

[Fact]
public async Task SearchDetailsAsync_WhenInvokeWithNullRating_ShouldGetData()
{
    //Arrange
    var context = CreateContext();
    var templateSearcher = await CreateTemplateSearcherAsync(context);
    var expectedTemplateId = 1;
    var templateToGet = await context.Set<Template>().Where(temp => temp.Id == expectedTemplateId).SingleAsync();

    //Act
    var result = await templateSearcher.SearchDetailsAsync(default, templateToGet.Key);

    //Assert
    Assert.NotNull(result);

    ContextTestHelper.Dispose(templateSearcher);
}

测试的调用栈信息如下:

Message: 
System.InvalidOperationException : Nullable object must have a value.

Stack Trace:

lambda_method2119(Closure, ValueBuffer)
WhereSelectEnumerableIterator`2.MoveNext()
Enumerable.TryGetSingle[TSource](IEnumerable`1 source, Boolean& found)
lambda_method2091(Closure)
ResultEnumerable.GetEnumerator()
Enumerator.MoveNextHelper()
Enumerator.MoveNextAsync()
ShapedQueryCompilingExpressionVisitor.SingleOrDefaultAsync[TSource](IAsyncEnumerable`1 asyncEnumerable, CancellationToken cancellationToken)
ShapedQueryCompilingExpressionVisitor.SingleOrDefaultAsync[TSource](IAsyncEnumerable`1 asyncEnumerable, CancellationToken cancellationToken)
TemplateSearcher.SearchDetailsAsync(CancellationToken cancellationToken, Guid templateKey) line 41
TemplateSearcherTests.SearchDetailsAsync_WhenInvokeWithNullRating_ShouldGetData() line 554
--- End of stack trace from previous location ---

更新2:
生成的SQL语句如下:

DECLARE @__ef_filter__TenantId_1 varchar(50) = 'xxxxxxxx';
DECLARE @__ef_filter__TenantId_2 varchar(50) = 'xxxxxxxx';
DECLARE @__ef_filter__TenantId_0 varchar(50) = 'xxxxxxxx';
DECLARE @__templateKey_0 uniqueIdentifier = 'some-guid-key';

SELECT [f].[Key], CASE
    WHEN [t].[Id] IS NULL THEN CAST(1 AS bit)
    ELSE CAST(0 AS bit)
END, [t].[Legend], CAST([t].[RangeTypeId] AS tinyint), [f].[Id], [t].[Id], [t0].[Id], [t0].[Value]
FROM [template].[Templates] AS [f]
LEFT JOIN (
    SELECT [r].[Id], [r].[Legend], [r].[RangeTypeId]
    FROM [template].[RangesDefinitions] AS [r]
    WHERE [r].[TenantId] = @__ef_filter__TenantId_1
) AS [t] ON [f].[FinalRatingRangeId] = [t].[Id]
LEFT JOIN (
    SELECT [r0].[Id], [r0].[Text], [r0].[RangeDefinitionId]
    FROM [template].[RangesValues] AS [r0]
    WHERE [r0].[TenantId] = @__ef_filter__TenantId_2
) AS [t0] ON [t].[Id] = [t0].[RangeDefinitionId]
WHERE [f].[TenantId] = @__ef_filter__TenantId_0 AND [f].[Key] = @__templateKey_0
ORDER BY [f].[Id], [t].[Id]

有趣的是,该SQL执行正常,所以可能是模拟数据或内存数据库的问题,正在排查中。感谢Nikola建议查看生成的查询语句!


更新3:
测试发现仅当内存数据库存在子查询的null数据时才会报错,其他内存数据库测试正常,而SQL数据库在所有场景下都正常运行。因此推测是内存数据库的问题,我将评估切换为SQLite In-Memory的可行性。

非常感谢大家的帮助!


内容的提问来源于stack exchange,提问作者Marco Nuñez

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 04:00:06