实体框架核心:“ SqlNullValueException:数据为空。”如何解决问题?

Eho*_*ret 3 c# entity-framework-core .net-core asp.net-core

我在ASP.NET Core应用程序和Controller动作中使用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);
}
Run Code Online (Sandbox Code Playgroud)

痕迹

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)
Microsoft.EntityFrameworkCore.Query.Internal.AsyncQueryingEnumerable<T>+AsyncEnumerator.MoveNext(CancellationToken cancellationToken)
Microsoft.EntityFrameworkCore.Query.Internal.AsyncLinqOperatorProvider+ExceptionInterceptor<T>+EnumeratorExceptionInterceptor.MoveNext(CancellationToken cancellationToken)
System.Linq.AsyncEnumerable.Aggregate_<TSource, TAccumulate, TResult>(IAsyncEnumerable<TSource> source, TAccumulate seed, Func<TAccumulate, TSource, TAccumulate> accumulator, Func<TAccumulate, TResult> resultSelector, CancellationToken cancellationToken) in Aggregate.cs
KYC.Core.Areas.Commercial.Controllers.CompaniesController.Index() in CompaniesController.cs
-
        [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();
lambda_method(Closure , object )
Microsoft.Extensions.Internal.ObjectMethodExecutorAwaitable+Awaiter.GetResult()
Microsoft.AspNetCore.Mvc.Internal.ActionMethodExecutor+TaskOfActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, object controller, object[] arguments)
System.Threading.Tasks.ValueTask<TResult>.get_Result()
Run Code Online (Sandbox Code Playgroud)

我什至试着做var companies = await DB.Companies.ToListAsync()。和我有完全一样的例外。

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

我想知道可能会发生什么。特别是由于仍然可以从数据库中获取其他实体,例如用户或国家/地区。

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

[编辑]

在“代码”中唯一实际更改的是nuget引用,我基本上升级了几乎所有内容,尽管它并没有破坏代码中的引用,似乎它改变了EF Core以某种方式(疯狂猜测)解释数据库的方式。

我确实在nuget软件包更新发生并且工作正常之前将git存储库重置为该点。然后,我决定只是将EntityFrameworkCore从2.0.2更新到2.2.4(也尝试使用2.2.0并最终得到相同的结果),问题再次发生...不确定2.0.2和2.2之间的变化。 0触发此异常(但模型相同,只是更改了EF Core版本)...

这是实体定义,似乎已经使用数据库表/架构中的工具自动生成了:


    [Table("T_Companies")]
    public partial class Company : INotifyPropertyChanging, INotifyPropertyChanged
    {
        public override string ToString()
        {
            return CompanyId + " " + CompanyName;
        }

        private static PropertyChangingEventArgs emptyChangingEventArgs = new PropertyChangingEventArgs(string.Empty);

        private int _CompanyId;

        private string _CompanyName;

        private int _CompanyTypeId;

        private int _CountryId;

        private string _CompanyVatNumber;

        private string _CompanyStreetAddress;

        private string _CompanyZipCode;

        private string _CompanyCity;

        private string _ContactLastName;

        private string _ContactFirstName;

        private bool? _Active;

        private int? _AccountId;

        private string _CallbackSalt;

        private int? _UserSpaceId;

        private string _Login;

        private string _Pwd;

        private bool _IsTechnicalAccount;

        private DateTime? _StatusDate;

        private int _BankStatusCode;

        private string _PivotalAccount;

        private CompanyType _CompanyType;

        private Country _Country;

        private bool _IsKycIdSent;

        #region Extensibility Method Definitions
        partial void OnLoaded();
        partial void OnCreated();
        partial void OnCompanyIdChanging(int value);
        partial void OnCompanyIdChanged();
        partial void OnCompanyNameChanging(string value);
        partial void OnCompanyNameChanged();

        partial void OnCompanyCityChanging(string value);
        partial void OnCompanyCityChanged();
        partial void OnCompanyZipCodeChanging(string value);
        partial void OnCompanyZipCodeChanged();
        partial void OnContactLastNameChanging(string value);
        partial void OnContactLastNameChanged();
        partial void OnActiveChanging(bool? value);
        partial void OnActiveChanged();
        partial void OnCompanyTypeIdChanging(int value);
        partial void OnCompanyTypeIdChanged();
        partial void OnCountryIdChanging(int value);
        partial void OnCountryIdChanged();
        partial void OnContactFirstNameChanging(string value);
        partial void OnContactFirstNameChanged();
        partial void OnCompanyVatNumberChanging(string value);
        partial void OnCompanyVatNumberChanged();
        partial void OnCompanyStreetAddressChanged();
        partial void OnCompanyStreetAddressChanging(string value);
        partial void OnAccountIdChanging(int? value);
        partial void OnAccountIdChanged();
        partial void OnCallbackSaltChanging(string value);
        partial void OnCallbackSaltChanged();
        partial void OnUserSpaceIdChanging(int? value);
        partial void OnUserSpaceIdChanged();
        partial void OnLoginChanging(string value);
        partial void OnLoginChanged();
        partial void OnPwdChanging(string value);
        partial void OnPwdChanged();
        partial void OnIsTechnicalAccountChanging(bool value);
        partial void OnIsTechnicalAccountChanged();
        partial void OnStatusDateChanging(DateTime? value);
        partial void OnStatusDateChanged();
        partial void OnBankStatusCodeChanging(int value);
        partial void OnBankStatusCodeChanged();
        partial void OnPivotalAccountChanging(string value);
        partial void OnPivotalAccountChanged();
        partial void OnIsKycIdSentChanging(bool value);
        partial void OnIsKycIdSentChanged();

        #endregion

        public Company()
        {
            OnCreated();
        }

        [Key, Column("CompanyId"), DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int CompanyId
        {
            get => _CompanyId;
            set
            {
                if (_CompanyId != value)
                {
                    OnCompanyIdChanging(value);
                    SendPropertyChanging();
                    _CompanyId = value;
                    SendPropertyChanged("CompanyId");
                    OnCompanyIdChanged();
                }
            }
        }

        [DataType(DataType.Text), StringLength(1024), Column("CompanyName"), Required]
        public string CompanyName
        {
            get => _CompanyName;
            set
            {
                if (_CompanyName != value)
                {
                    OnCompanyNameChanging(value);
                    SendPropertyChanging();
                    _CompanyName = value;
                    SendPropertyChanged("CompanyName");
                    OnCompanyNameChanged();
                }
            }
        }

        [Column("CompanyTypeId"), Required]
        public int CompanyTypeId
        {
            get => _CompanyTypeId;
            set
            {
                if (_CompanyTypeId != value)
                {
                    OnCompanyTypeIdChanging(value);
                    SendPropertyChanging();
                    _CompanyTypeId = value;
                    SendPropertyChanged("CompanyTypeId");
                    OnCompanyTypeIdChanged();
                }
            }
        }


        [Column("CountryId"), Required]
        public int CountryId
        {
            get => _CountryId;
            set
            {
                if (CountryId != value)
                {
                    OnCountryIdChanging(value);
                    SendPropertyChanging();
                    _CountryId = value;
                    SendPropertyChanged("CountryId");
                    OnCountryIdChanged();
                }
            }
        }


        [DataType(DataType.Text), StringLength(100), Column("CompanyCity"), Required]
        public string CompanyCity
        {
            get => _CompanyCity;
            set
            {
                if (_CompanyCity != value)
                {
                    OnCompanyCityChanging(value);
                    SendPropertyChanging();
                    _CompanyCity = value;
                    SendPropertyChanged("CompanyCity");
                    OnCompanyCityChanged();
                }
            }
        }

        [DataType(DataType.Text), StringLength(100), Column("CompanyStreetAddress"), Required]
        public string CompanyStreetAddress
        {
            get => _CompanyStreetAddress;
            set
            {
                if (_CompanyStreetAddress != value)
                {
                    OnCompanyStreetAddressChanging(value);
                    SendPropertyChanging();
                    _CompanyStreetAddress = value;
                    SendPropertyChanged("CompanyStreetAddress");
                    OnCompanyStreetAddressChanged();
                }
            }
        }

        [DataType(DataType.Text), StringLength(30), Column("CompanyVatNumber"), Required]
        public string CompanyVatNumber
        {
            get => _CompanyVatNumber;
            set
            {
                if (_CompanyVatNumber != value)
                {
                    OnCompanyVatNumberChanging(value);
                    SendPropertyChanging();
                    _CompanyVatNumber = value;
                    SendPropertyChanged("CompanyVatNumber");
                    OnCompanyVatNumberChanged();
                }
            }
        }


        [DataType(DataType.Text), StringLength(10), Column("CompanyZipCode"), Required]
        public string CompanyZipCode
        {
            get => _CompanyZipCode;
            set
            {
                if (_CompanyZipCode != value)
                {
                    OnCompanyZipCodeChanging(value);
                    SendPropertyChanging();
                    _CompanyZipCode = value;
                    SendPropertyChanged("CompanyZipCode");
                    OnCompanyZipCodeChanged();
                }
            }
        }


        [DataType(DataType.Text), StringLength(1024), Column("ContactLastName"), Required]
        public string ContactLastName
        {
            get => _ContactLastName;
            set
            {
                if (_ContactLastName != value)
                {
                    OnContactLastNameChanging(value);
                    SendPropertyChanging();
                    _ContactLastName = value;
                    SendPropertyChanged("ContactLastName");
                    OnContactLastNameChanged();
                }
            }
        }

        [DataType(DataType.Text), StringLength(1024), Column("ContactFirstName"), Required]
        public string ContactFirstName
        {
            get => _ContactFirstName;
            set
            {
                if (_ContactFirstName != value)
                {
                    OnContactFirstNameChanging(value);
                    SendPropertyChanging();
                    _ContactFirstName = value;
                    SendPropertyChanged("ContactFirstName");
                    OnContactFirstNameChanged();
                }
            }
        }

        [Column("Active"), Required]
        public bool? Active
        {
            get => _Active;
            set
            {
                if (_Active != value)
                {
                    OnActiveChanging(value);
                    SendPropertyChanging();
                    _Active = value;
                    SendPropertyChanged("Active");
                    OnActiveChanged();
                }
            }
        }

        [Column("AccountId")]
        public int? AccountId
        {
            get => _AccountId;
            set
            {
                if (_AccountId != value)
                {
                    OnAccountIdChanging(value);
                    SendPropertyChanging();
                    _AccountId = value;
                    SendPropertyChanged("AccountId");
                    OnAccountIdChanged();
                }
            }
        }

        [DataType(DataType.Text), StringLength(1024), Column("CallbackSalt")]
        public string CallbackSalt
        {
            get => _CallbackSalt;
            set
            {
                if (_CallbackSalt != value)
                {
                    OnCallbackSaltChanging(value);
                    SendPropertyChanging();
                    _CallbackSalt = value;
                    SendPropertyChanged("CallbackSalt");
                    OnCallbackSaltChanged();
                }
            }
        }

        [Column("UserSpaceId")]
        public int? UserSpaceId
        {
            get => _UserSpaceId;
            set
            {
                if (_UserSpaceId != value)
                {
                    OnUserSpaceIdChanging(value);
                    SendPropertyChanging();
                    _UserSpaceId = value;
                    SendPropertyChanged("UserSpaceId");
                    OnUserSpaceIdChanged();
                }
            }
        }

        [DataType(DataType.Text), StringLength(1024), Column("Login")]
        public string Login
        {
            get => _Login;
            set
            {
                if (_Login != value)
                {
                    OnLoginChanging(value);
                    SendPropertyChanging();
                    _Login = value;
                    SendPropertyChanged("Login");
                    OnLoginChanged();
                }
            }
        }

        [DataType(DataType.Text), StringLength(1024), Column("Pwd")]
        public string Pwd
        {
            get => _Pwd;
            set
            {
                if (_Pwd != value)
                {
                    OnPwdChanging(value);
                    SendPropertyChanging();
                    _Pwd = value;
                    SendPropertyChanged("Pwd");
                    OnPwdChanged();
                }
            }
        }

        [Column("IsTechnicalAccount"), Required]
        public bool IsTechnicalAccount
        {
            get => _IsTechnicalAccount;
            set
            {
                if (_IsTechnicalAccount != value)
                {
                    OnIsTechnicalAccountChanging(value);
                    SendPropertyChanging();
                    _IsTechnicalAccount = value;
                    SendPropertyChanged("IsTechnicalAccount");
                    OnIsTechnicalAccountChanged();
                }
            }
        }

        [DataType(DataType.DateTime), Column("StatusDate")]
        public DateTime? StatusDate
        {
            get => _StatusDate;
            set
            {
                if (_StatusDate != value)
                {
                    OnStatusDateChanging(value);
                    SendPropertyChanging();
                    _StatusDate = value;
                    SendPropertyChanged("StatusDate");
                    OnStatusDateChanged();
                }
            }
        }

        [Column("BankStatusCode")]
        public int BankStatusCode
        {
            get => _BankStatusCode;
            set
            {
                if (_BankStatusCode != value)
                {
                    OnBankStatusCodeChanging(value);
                    SendPropertyChanging();
                    _BankStatusCode = value;
                    SendPropertyChanged("BankStatusCode");
                    OnBankStatusCodeChanged();
                }
            }
        }

        [DataType(DataType.Text), StringLength(255), Column("PivotalAccount")]
        public string PivotalAccount
        {
            get => _PivotalAccount;
            set
            {
                if (_PivotalAccount != value)
                {
                    OnPivotalAccountChanging(value);
                    SendPropertyChanging();
                    _PivotalAccount = value;
                    SendPropertyChanged("PivotalAccount");
                    OnPivotalAccountChanged();
                }
            }
        }

        public List<Resultat> Resultats { get; set; }

        public CompanyType CompanyType
        {
            get => _CompanyType;
            set
            {
                var previousValue = _CompanyType;
                if (previousValue != value)
                {
                    SendPropertyChanging();
                    _CompanyType = value;
                    if (value != null)
                    {
                        CompanyTypeId = value.CompanyTypeId;
                    }
                    else
                    {
                        _CompanyTypeId = default;
                    }
                    SendPropertyChanged("CompanyType");
                }
            }
        }

        public Country Country
        {
            get => _Country;
            set
            {
                var previousValue = _Country;
                if (previousValue != value)
                {
                    SendPropertyChanging();
                    _Country = value;
                    _CountryId = value?.CountryId ?? default;
                    SendPropertyChanged("Country");
                }
            }
        }

        [Column("IsKycIdSent"), Required]
        public bool IsKycIdSent
        {
            get => _IsKycIdSent;
            set
            {
                if (_IsKycIdSent != value)
                {
                    OnIsKycIdSentChanging(value);
                    SendPropertyChanging();
                    _IsKycIdSent = value;
                    SendPropertyChanged("IsKycIdSent");
                    OnIsKycIdSentChanged();
                }
            }
        }

        public event PropertyChangingEventHandler PropertyChanging;

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void SendPropertyChanging()
        {
            PropertyChanging?.Invoke(this, emptyChangingEventArgs);
        }

        protected virtual void SendPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArg

Jog*_*gge 30

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

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

public class MyEntity
{
    public int Id { get; set; }
    public int MyInt { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

你会得到异常: System.Data.SqlTypes.SqlNullValueException: 'Data is Null. This method or property cannot be called on Null values.'

要解决此问题,只需将您的MyInt属性类型更改为Nullable<int>int?

public class MyEntity
{
    public int Id { get; set; }
    public int? MyInt { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

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

  • 我喜欢你的“注意:”——这是客户要求的和他们实际想要的之间的区别。 (2认同)

ado*_*ace 9

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

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

public class MyEntity
{
   public string MyProperty { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

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

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

  • 简而言之:使用 C# 8,MyProperty 需要是字符串?如果它是数据库中可为空的值。 (7认同)

Gui*_*rez 9

解决方案:是的,错误“SqlNullValueException:数据为空”。当模型将导致问题的字段标记为 [Required] 时,(表的)列包含 NULL 时会导致问题...使用数字字段很容易解决问题,但当字段为字符串类型时,问题确实很糟糕。 。

想想下面两个使用分发路线示例的类,每条路线都有一个司机,当然,每个司机都有 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>();

    }
Run Code Online (Sandbox Code Playgroud)

正如您可能猜到的,一条路线可以有一个驱动程序(或我所说的 Usuario),但一个驱动程序可以有多个路线,这形成了一对多关系,如下所示:

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);
                
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

modelBuilder.Entity<Route>()
   .Property(p => p.UsuarioId).IsRequired(required: false);
Run Code Online (Sandbox Code Playgroud)

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


Iva*_*oev 8

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

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

因此,问题是由这些列中的一个或多个引起的。

您需要解决该差异-可能是通过删除[Required]属性,因为约束已在现有数据中打破。

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

  • 谢谢,这实际上是根本问题~~不知道 EF Core 在早期阶段对 bug 更加“宽容”,以至于放弃了一些列约束。感谢您指出了这一点。 (3认同)
  • 就我而言,一旦我在项目级别激活可为空引用类型,而没有对实体类进行必要的更改,此错误就开始出现。禁用该功能就可以了。 (2认同)

ski*_*rks 7

如果您想忽略这些值,可以添加 DefaultIfEmpty() 。

_context.<YourDbSet>.DefaultIfEmpty().ToListAsync();
Run Code Online (Sandbox Code Playgroud)

在这种情况下:

var companyEditVMs = await DB.Companies
    .OrderBy(company => company.CompanyId == 1 
        ? "_" + company.CompanyName 
        : company.CompanyName
    )
    Select(a => new CompanyEditVM(..--..)).DefaultIfEmpty()
    .ToListAsync();
Run Code Online (Sandbox Code Playgroud)


cry*_*yss 6

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

builder.Property(x => x.MyProperty).IsRequired(false);
Run Code Online (Sandbox Code Playgroud)

  • 执行此操作后发现,由于我所讨论的列是复合键的一部分,因此 EF 自动将其标记为必需,从而导致了问题。这并没有解决问题,但却暴露了问题。TVM (2认同)

bob*_*obt 5

就我而言,这是因为我将数据库中的列从不可为空更改为可空,然后忘记了我需要再次重新运行 Scaffold-DbContext 以便更新实体类。我正在使用数据库优先的 Entity Framework Core。