为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

C#
繁星淼淼 2022-12-31 13:55:58
我在 ASP.NET Core 应用程序和控制器操作中使用 Entity Framework Core,我没有对工作代码或数据库进行任何更改,但我无法判断 Entity Framework Core 执行的查询是什么。控制器动作:[HttpGet]// GET: Administration/Companiespublic 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 执行的查询以手动执行此操作,以便我可以尝试找出查询有什么问题。我想知道可能发生了什么。特别是因为仍然可以从数据库中获取用户或国家等其他实体。知道如何解决实际的潜在问题吗?
查看完整描述

5 回答

?
子衿沉夜

TA贡献1828条经验 获得超3个赞

错误消息表明 EF Core 正在尝试读取所需string属性的值,即不应在数据库中具有值的属性而是底层数据读取器在某些记录中报告该属性的值。nullnull

查看您的实体模型和相应的数据库表,您可以看到许多string属性 ->varchar列的明显差异。CompanyStreetAddressCompanyCityCompanyZipCodeCompanyVatNumberContactFirstNameContactLastName- 所有这些都[Required]在模型中标记为,但在表中没有相应not null的约束。

所以问题是由这些列中的一个或多个引起的。

您需要修复该差异 - 可能通过删除[Required]属性来解决,因为现有数据中的约束已被破坏。

它在某些较旧的 EF Core 版本中“有效”这一事实并不重要——这是不正确的映射,因此应该修复。从技术上讲,它不应该从一开始就起作用。但请记住,EF Core 仍在积极开发中,并且有许多错误将在下一个版本中修复。很可能在“工作”和“非工作”EF Core 版本之间进行了一些代码更改,这修复了以前的不正确行为。


查看完整回答
反对 回复 2022-12-31
?
慕斯709654

TA贡献1840条经验 获得超5个赞

如果您尝试从数据库中读取一些可为空的数据,但您的类型不可为空,则可能会出现此错误。


如果MyInt在数据库中可以为空并且您有此实体:


public class MyEntity

{

    public int Id { get; set; }

    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

{

    public int Id { get; set; }

    public int? MyInt { get; set; }

}

注意:这不是对原问题的回答,而是对标题中问题的回答。


查看完整回答
反对 回复 2022-12-31
?
守着一只汪

TA贡献1872条经验 获得超3个赞

如果您从 C# 8 启用最新的 Nullable 功能,也会出现这种异常。

EF Core,至少目前,它与 C# 8 可空类型不完全兼容。因此,例如,假设您为项目启用了 Nullable 功能,如果您有这样的类型:

public class MyEntity{
   public string MyProperty { get; set; }
}

即使该属性标记 [Required] 属性,EF 核心也会引发此类异常,因为它要求数据库中的值不为空(即它不使用 IsDbNull 测试列值)。

有关如何在 EF 核心中处理可空引用类型的更多信息,请查看: https ://learn.microsoft.com/en-us/ef/core/miscellaneous/nullable-reference-types


查看完整回答
反对 回复 2022-12-31
?
婷婷同学_

TA贡献1844条经验 获得超8个赞

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

builder.Property(x => x.MyProperty).IsRequired(false);


查看完整回答
反对 回复 2022-12-31
?
慕雪6442864

TA贡献1812条经验 获得超5个赞

解决方案:是的,错误“SqlNullValueException:数据为空。” 当模型将导致问题的字段标记为 [Required] 时,当(表的)列包含 NULL 时引起...使用数字字段可以轻松解决问题,但当字段类型为字符串时问题非常糟糕。 .


想想下面2个类,用了一个分配路线的例子,每条路线都有一个司机,当然每个司机都有1条或多条路线。


public class Route

    {

        public int id { get; set; }       

        public string RouteName { get; set; }


        [Required] \\==> FIELD CAUSING THE PROBLEM

        public string UsuarioId { get; set; }


        public virtual Usuario Driver { get; set; }

}


public class Usuario

    {

        public string Id {get;set;

        public string Name { get; set; }                

        public virtual List<Route> Routes { get; set; } = new List<Route>();


    }


你可能猜到了,一个 Route 可以有一个 driver(或者我称之为 Usuario),但是一个 Driver 可以有多个 route,这就构成了一对多的关系,如下所示:


protected override void OnModelCreating(ModelBuilder modelBuilder){            


     base.OnModelCreating(modelBuilder);


     modelBuilder.Entity<Usuario>()

        .HasMany<Route>(usuario => usuario.Routes)

        .WithOne(route => route.Driver)

        .HasForeignKey(route => route.UsuarioId)

        .OnDelete(DeleteBehavior.SetNull);

                

}


根据 FluentAPI,删除驱动程序时,行为是将 UsuarioId 字段(在 Routes 模型中)设置为 NULL,但这违反了 [Required] 属性。所以我们将无法删除 Users(或 Drivers)表中的记录。此外,如果我们在数据库中已有数据,在本例中,Routes with NULL UsuarioId,它会立即显示错误。


请记住,重点是:我们希望 [Required] 仅用于验证目的,因为我们可能拥有尚未分配给驱动程序(UserId)的路由,因此在数据库中,它应该被允许为 NULL ,而不是我们的 mvc 形式。


要解决此问题,请将该字段标记为 [required],然后转到您使用 Fluent API 定义关系的 DbContext 类,并指定该列不是必需的,如下所示:


modelBuilder.Entity<Route>()

   .Property(p => p.UsuarioId).IsRequired(required: false);


因此该字段现在在注释模式下是必需的,但最终将用于构建数据库的流式 API 不需要该字段。这将解决问题!


查看完整回答
反对 回复 2022-12-31
  • 5 回答
  • 0 关注
  • 383 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信