Entity Framework Core:`SqlNullValueException:数据为空。

我在 ASP.NET Core 应用程序和控制器操作中使用 Entity Framework Core,我没有对工作代码或数据库进行任何更改,但我无法判断 Entity Framework Core 执行的查询是什么。


控制器动作:


[HttpGet]

// GET: Administration/Companies

public async Task<ActionResult> Index()

{

    var users = await UserManager.Users.ToListAsync();


    var companyEditVMs = await DB.Companies

    .OrderBy(company => company.CompanyId == 1 

        ? "_" + company.CompanyName 

        : company.CompanyName

    )

    Select(a => new CompanyEditVM(HttpContext, a, users.Where(b => b.CompanyId == a.CompanyId)))

    .ToListAsync();


    return View(companyEditVMs);

}

痕迹


SqlNullValueException: Data is Null. This method or property cannot be called on Null values.

System.Data.SqlClient.SqlBuffer.get_String()

System.Data.SqlClient.SqlDataReader.GetString(int i)

lambda_method(Closure , DbDataReader )

Microsoft.EntityFrameworkCore.Storage.Internal.TypedRelationalValueBufferFactory.Create(DbDataReader dataReader)

Microsoft.EntityFrameworkCore.Query.Internal.AsyncQueryingEnumerable<T>+AsyncEnumerator.BufferlessMoveNext(DbContext _, bool buffer, CancellationToken cancellationToken)

Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.ExecuteAsync<TState, TResult>(TState state, Func<DbContext, TState, CancellationToken, Task<TResult>> operation, Func<DbContext, TState, CancellationToken, Task<ExecutionResult<TResult>>> verifySucceeded, CancellationToken cancellationToken)


我什至试着做 just var companies = await DB.Companies.ToListAsync()。我有完全相同的例外。


也许我希望能够获取 EF Core 执行的查询以手动执行此操作,以便我可以尝试找出查询有什么问题。


我想知道可能发生了什么。特别是因为仍然可以从数据库中获取用户或国家等其他实体。


知道如何解决实际的潜在问题吗?


繁星淼淼
浏览 384回答 5
5回答

子衿沉夜

错误消息表明 EF Core 正在尝试读取所需string属性的值,即不应在数据库中具有值的属性,而是底层数据读取器在某些记录中报告该属性的值。nullnull查看您的实体模型和相应的数据库表,您可以看到许多string属性 ->varchar列的明显差异。CompanyStreetAddress,&nbsp;CompanyCity,&nbsp;CompanyZipCode,&nbsp;CompanyVatNumber,&nbsp;ContactFirstName,&nbsp;ContactLastName- 所有这些都[Required]在模型中标记为,但在表中没有相应not null的约束。所以问题是由这些列中的一个或多个引起的。您需要修复该差异 - 可能通过删除[Required]属性来解决,因为现有数据中的约束已被破坏。它在某些较旧的 EF Core 版本中“有效”这一事实并不重要——这是不正确的映射,因此应该修复。从技术上讲,它不应该从一开始就起作用。但请记住,EF Core 仍在积极开发中,并且有许多错误将在下一个版本中修复。很可能在“工作”和“非工作”EF Core 版本之间进行了一些代码更改,这修复了以前的不正确行为。

慕斯709654

如果您尝试从数据库中读取一些可为空的数据,但您的类型不可为空,则可能会出现此错误。如果MyInt在数据库中可以为空并且您有此实体:public class MyEntity{&nbsp; &nbsp; public int Id { get; set; }&nbsp; &nbsp; public int MyInt { get; set; }}你会得到例外:System.Data.SqlTypes.SqlNullValueException: 'Data is Null. This method or property cannot be called on Null values.'MyInt要解决此问题,只需将属性的类型更改为Nullable<int>or int?:public class MyEntity{&nbsp; &nbsp; public int Id { get; set; }&nbsp; &nbsp; public int? MyInt { get; set; }}注意:这不是对原问题的回答,而是对标题中问题的回答。

守着一只汪

如果您从 C# 8 启用最新的 Nullable 功能,也会出现这种异常。EF Core,至少目前,它与 C# 8 可空类型不完全兼容。因此,例如,假设您为项目启用了 Nullable 功能,如果您有这样的类型:public&nbsp;class&nbsp;MyEntity{ &nbsp;&nbsp;&nbsp;public&nbsp;string&nbsp;MyProperty&nbsp;{&nbsp;get;&nbsp;set;&nbsp;} }即使该属性未标记 [Required] 属性,EF 核心也会引发此类异常,因为它要求数据库中的值不为空(即它不使用 IsDbNull 测试列值)。有关如何在 EF 核心中处理可空引用类型的更多信息,请查看:&nbsp;https ://learn.microsoft.com/en-us/ef/core/miscellaneous/nullable-reference-types

婷婷同学_

为了解决类似的Data is Null异常问题,我必须明确地放置IsRequired(false)我的列映射。在我的例子中,我正在映射一个数据库视图。builder.Property(x&nbsp;=>&nbsp;x.MyProperty).IsRequired(false);

慕雪6442864

解决方案:是的,错误“SqlNullValueException:数据为空。” 当模型将导致问题的字段标记为 [Required] 时,当(表的)列包含 NULL 时引起...使用数字字段可以轻松解决问题,但当字段类型为字符串时问题非常糟糕。 .想想下面2个类,用了一个分配路线的例子,每条路线都有一个司机,当然每个司机都有1条或多条路线。public class Route&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; public int id { get; set; }&nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; public string RouteName { get; set; }&nbsp; &nbsp; &nbsp; &nbsp; [Required] \\==> FIELD CAUSING THE PROBLEM&nbsp; &nbsp; &nbsp; &nbsp; public string UsuarioId { get; set; }&nbsp; &nbsp; &nbsp; &nbsp; public virtual Usuario Driver { get; set; }}public class Usuario&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; public string Id {get;set;&nbsp; &nbsp; &nbsp; &nbsp; public string Name { get; set; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; public virtual List<Route> Routes { get; set; } = new List<Route>();&nbsp; &nbsp; }你可能猜到了,一个 Route 可以有一个 driver(或者我称之为 Usuario),但是一个 Driver 可以有多个 route,这就构成了一对多的关系,如下所示:protected override void OnModelCreating(ModelBuilder modelBuilder){&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp; &nbsp; &nbsp;base.OnModelCreating(modelBuilder);&nbsp; &nbsp; &nbsp;modelBuilder.Entity<Usuario>()&nbsp; &nbsp; &nbsp; &nbsp; .HasMany<Route>(usuario => usuario.Routes)&nbsp; &nbsp; &nbsp; &nbsp; .WithOne(route => route.Driver)&nbsp; &nbsp; &nbsp; &nbsp; .HasForeignKey(route => route.UsuarioId)&nbsp; &nbsp; &nbsp; &nbsp; .OnDelete(DeleteBehavior.SetNull);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;}根据 FluentAPI,删除驱动程序时,行为是将 UsuarioId 字段(在 Routes 模型中)设置为 NULL,但这违反了 [Required] 属性。所以我们将无法删除 Users(或 Drivers)表中的记录。此外,如果我们在数据库中已有数据,在本例中,Routes with NULL UsuarioId,它会立即显示错误。请记住,重点是:我们希望 [Required] 仅用于验证目的,因为我们可能拥有尚未分配给驱动程序(UserId)的路由,因此在数据库中,它应该被允许为 NULL ,而不是我们的 mvc 形式。要解决此问题,请将该字段标记为 [required],然后转到您使用 Fluent API 定义关系的 DbContext 类,并指定该列不是必需的,如下所示:modelBuilder.Entity<Route>()&nbsp; &nbsp;.Property(p => p.UsuarioId).IsRequired(required: false);因此该字段现在在注释模式下是必需的,但最终将用于构建数据库的流式 API 不需要该字段。这将解决问题!
打开App,查看更多内容
随时随地看视频慕课网APP