【问题标题】:I upgraded from .NET 5 to .NET 6 and now getting SqlNullValueException from a LINQ query我从 .NET 5 升级到 .NET 6,现在从 LINQ 查询中获取 SqlNullValueException
【发布时间】:2021-12-09 17:49:58
【问题描述】:

我刚刚将一个项目从 .NET 5 升级到 .NET 6 预览版,并开始使用 Visual Studio 2022。但我得到了一个以前没有得到的 SqlNullValueException。这对我来说没有意义。

这是 LINQ 查询:

var clients = _dbContext.AppUserAppUsers
            .Where(x => x.AppUserParentId == designerId
                        && x.ChildAppUser.AppUserRole == AppUserRole.Client)
            .Include(x => x.ChildAppUser.Profile)
            .Select(x => x.ChildAppUser)
            .AsNoTracking();

return clients.ToList();

AppUserAppUsers 实体是 AppUsers 的多对多模型。我正在使用 Table-per-hierarchy pattern 所以我有 AppUserBase 抽象类,DesignerModel 和 ClientModel 都扩展了该类。

public class AppUserAppUser
    {
        public int AppUserParentId { get; set; }

        public int AppUserChildId { get; set; }

        public bool Active { get; set; }

        public AppUserBase ParentAppUser { get; set; }

        public AppUserBase ChildAppUser { get; set; }
    }

同样,所有这一切在 .NET 5 中都能完美运行!

对 ToList() 的调用会引发此异常:

System.Data.SqlTypes.SqlNullValueException
  HResult=0x80131931
  Message=Data is Null. This method or property cannot be called on Null values.
  Source=Microsoft.Data.SqlClient
  StackTrace:
   at Microsoft.Data.SqlClient.SqlBuffer.ThrowIfNull()
   at Microsoft.Data.SqlClient.SqlBuffer.get_String()
   at Microsoft.Data.SqlClient.SqlDataReader.GetString(Int32 i)
   at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.Enumerator.MoveNext()
   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
   at Design2WorkroomApi.Repository.AppUserRepository.GetClientsByDesignerId(Int32 designerId) in C:\Users\davew\source\repos\Design2WorkroomApi\Design2WorkroomApi\Repository\AppUserRepository.cs:line 65
   at Design2ClientAPI.Controllers.ClientsController.GetClientsByDesignerId(Int32 designerId) in C:\Users\davew\source\repos\Design2WorkroomApi\Design2WorkroomApi\Controllers\ClientsController.cs:line 56
   at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.SyncActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeActionMethodAsync()
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeNextActionFilterAsync()

如果我取出 Include 和 Select 调用,这工作正常。但是任何一个和 LINQ 语句都返回 null。

在 .NET 5 版本中,具有相同参数的相同方法可以正常工作。而且我之前用过很多次类似的代码都没有问题。

显然,.NET 6 中的某些内容已更改为导致此问题,但我不知道它是什么。

这是我的 Entity Framework Core 包。在升级这些软件包之前,我遇到了同样的问题。

 <PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="6.0.0-rc.2.21480.10" />
    <PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.0-rc.2.21480.5" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.0-rc.2.21480.5" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.0-rc.2.21480.5">

【问题讨论】:

  • 1) AppUserBase 有问题,数据库中的某些字符串字段为空,但 EF 不知道这一点,请检查您的模型。 2)。 IncludeSelect 两个相反的运算符,如果有SelectInclude 可以省略。
  • 谢谢。我在 AppUser 中有一个具有空值的字符串属性。我让它可以为空,它现在可以工作了。但我不明白这一点。据我所知,C# 中的字符串在默认情况下始终可以为空。就像我说的那样,这在 .NET 5 中运行良好。现在很困惑,但它正在运行。另外,我确实删除了 Include 语句,但不再包含配置文件。所以我把它加回来了。那工作正常。我不知道有更好的方法来做到这一点。
  • 它是出于性能原因而制作的。如果每个字符串字段的 EF 都会检查 DB Null,则会降低性能。
  • 谢谢,我现在不那么困惑了。 :-)

标签: c# .net linq asp.net-core entity-framework-core


【解决方案1】:

删除.Include(),在这种特殊情况下不需要它,它可能会导致您遇到的错误。

新查询应该类似于:

var clients = _dbContext.AppUserAppUsers
            .Where(x => x.AppUserParentId == designerId
                        && x.ChildAppUser.AppUserRole == AppUserRole.Client)
            .Select(x => x.ChildAppUser)
            .AsNoTracking();

【讨论】:

  • 谢谢,但是当我省略包含语句时,它不包括配置文件。我试过了,但不得不把它放回去。该异常是由一个不可为空的字符串属性引起的,这是我以前从未见过的。在 C# 中默认情况下字符串不再可以为空吗?他们有没有借鉴 Kotlin 的经验?
  • @DavidEvans 这取决于,您可以通过在 csproj 文件(在第一个 &lt;PropertyGroup&gt; 标签内)添加 &lt;Nullable&gt;enable&lt;/Nullable&gt; 在项目中启用空检查,这将强制您的代码检查值可能的实例为空并警告您。完成后,您有两个选择,要么为 Profile 属性声明默认的 string.Empty 值,要么将其设为可空 string?。我希望这会有所帮助。
  • 确实如此。谢谢!
  • enable 行默认存在于新的 .NET 6 项目中。它不在新的 .NET 5 中。如果我删除该行并将字符串属性设置为不可为空,它可以正常工作。所以这就是为什么它在 .NET 5 版本而不是 .NET 6 中工作的原因。(我为 .NET 6 创建了一个新项目并做了一些复制和粘贴。)这就是为什么我真的很困惑。在 .NET 5 而不是 .NET 6 中工作。多亏了你,谜团才得以解开。我将启用 Nullable 并使字符串属性可以为空。
猜你喜欢
  • 1970-01-01
  • 2021-05-14
  • 1970-01-01
  • 2022-01-21
  • 2022-06-13
  • 2021-12-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多