linq 实体框架核心子查询:错误系统.InvalidOperationException:可为空的对象必须在

plicqrtu  于 2023-09-28  发布在  其他
关注(0)|答案(2)|浏览(141)

我在实体框架中有以下方法(为了简单起见,它的属性较少,但重要的是):

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:可为空的对象必须具有值
在这行代码中:

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

如果我评论这一部分,一切都像一个魅力。问题是ratingDef可以为null,而子查询会给我错误,因为ratingDef为null,所以,你认为我如何解决这个问题?
提前感谢!

**更新:**我正在使用这个进行测试(我正在使用内存数据库进行测试):

[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);
}

和测试结果的调用堆栈:
消息: System.InvalidOperationException:可为空的对象必须具有值。

堆栈跟踪:

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 ---

**更新二:**这是生成的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建议审核生成的查询!:D个

**更新3:**我正在做测试,只有在内存数据库中有来自子查询的一些空数据时才会发生错误。其余的SQL内存测试工作正常,现在SQL数据库在任何情况下都工作正常,所以正如他们提到的,这可能是内存中DB的问题,我将看看切换到SqlLite内存中的可行性如何。

非常感谢你们的帮助。

lskq00tm

lskq00tm1#

这部分代码可能是在内存中执行的,而不是翻译成sql。您可以在日志中或通过调用.ToQueryString()扩展方法检查生成的sql查询并进行验证。
我已经成功地解决了这种情况与LinqKit库。
顺便说一下,这里不需要NoTracking,因为结果是投影而不是跟踪实体。

jfewjypa

jfewjypa2#

正如我在更新3中提到的,这似乎是内存数据库的问题。
谢谢大家的帮助。

相关问题