Entity Framework Core: `SqlNullValueException: Data is Null.` 如何排查?
Posted
技术标签:
【中文标题】Entity Framework Core: `SqlNullValueException: Data is Null.` 如何排查?【英文标题】:Entity Framework Core: `SqlNullValueException: Data is Null.` How to troubleshoot? 【发布时间】:2019-09-16 22:01:38 【问题描述】:我在 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)
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()
我什至试着只做var companies = await DB.Companies.ToListAsync()
。我也有完全相同的例外。
也许我希望能够获取 EF Core 执行的查询以手动执行此操作,以便我可以尝试找出查询有什么问题。
我想知道可能会发生什么。特别是因为其他实体(如用户或国家/地区)仍然可以从数据库中获取。
知道如何解决实际的潜在问题吗?
[编辑]
“代码”中唯一真正改变的是 nuget 引用,我基本上升级了几乎所有东西,尽管它没有破坏代码中的引用,它似乎改变了 EF Core 以某种方式(疯狂猜测)解释数据库。
我确实将我的 git 存储库重置到 nuget 包更新发生并且一切正常之前的点。,。然后我决定将 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 PropertyChangedEventArgs(propertyName));
private void Attach_Resultats(Resultat entity)
SendPropertyChanging();
entity.Company = this;
private void Detach_Resultats(Resultat entity)
SendPropertyChanging();
entity.Company = null;
以及相关的建表脚本:
create table T_Companies
(
CompanyId int identity (10) identity
primary key nonclustered,
CompanyName varchar(1024) not null,
CompanyTypeId int not null
constraint FK_Company_CompanyType
references T_CompanyTypes,
CountryId int not null
constraint FK_Company_Country
references T_Countries,
Active bit not null,
AccountId int,
CallbackSalt varchar(1024),
UserSpaceId int,
Login varchar(1024),
Pwd varchar(1024),
StatusDate datetime(23, 3),
BankStatusCode int not null,
PivotalAccount varchar(255),
IsTechnicalAccount bit not null,
CompanyStreetAddress varchar(256),
CompanyCity varchar(256),
CompanyZipCode varchar(10),
CompanyVatNumber varchar(30),
ContactFirstName varchar(20),
ContactLastName varchar(20),
IsKycIdSent bit not null
)
go
[编辑 2]
对于相同的模型,这(在项目文件中的 nuget 引用)有效
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.1.8" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.1.8" />
而那些,没有:
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.2.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.2.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.2.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.1.8" />
【问题讨论】:
您的 EF 模型可能与数据库中的模型不匹配,很遗憾,我们无法帮助您修复它,因为我们看不到这两件事。这可能是您的模型中标记为非空的东西,但数据库允许空值。 另外,如果您在调用await DB.Companies.ToListAsync()
时遇到错误,那么您发布的其余代码完全是多余的 :)
@DavidG 用于调试目的
@DavidG 没有办法获得更好的跟踪或更准确的信息? :s
什么?您有异常消息,跟踪不会帮助您。给我们公司表的实体和表定义。
【参考方案1】:
错误消息表明 EF Core 正在尝试读取 必需 属性的 string
值,即应该永远在数据库,而是底层数据读取器在某些记录中报告该属性的 null
值。
查看您的实体模型和相应的数据库表,您可以看到许多string
属性-> varchar
列的明显差异。 CompanyStreetAddress
、CompanyCity
、CompanyZipCode
、CompanyVatNumber
、ContactFirstName
、ContactLastName
——这些都在模型中标记为[Required]
,但在表中没有对应的not null
约束。
所以问题是由这些列中的一个或多个引起的。
您需要修复该差异 - 可能通过删除 [Required]
属性,因为现有数据中的约束已被破坏。
它在某些较旧的 EF Core 版本中“工作”的事实并不重要 - 这是不正确的映射,因此应该修复。从技术上讲,它不应该从一开始就起作用。但请记住,EF Core 仍处于积极开发阶段,并且有许多错误将在下一个版本中修复。很可能在“工作”和“不工作”的 EF Core 版本之间进行了一些代码更改,从而修复了之前的不正确行为。
【讨论】:
谢谢,这实际上是根本问题 ~~ 不知道 EF Core 在早期阶段更“宽容”错误,以至于放弃了一些列约束。感谢您指出这一点。 在我的情况下,一旦我在项目级别激活可为空的引用类型,就开始出现此错误,而无需对我的实体类进行必要的更改。禁用该功能就可以了。【参考方案2】:如果您尝试从数据库中读取一些可为空的数据,但您的类型不可为空,您可能会收到此错误。
如果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>
或 int?
:
public class MyEntity
public int Id get; set;
public int? MyInt get; set;
注意:这不是对原始问题的回答,而是对标题中问题的回答。
【讨论】:
相关问题/答案:***.com/q/62015584/7108481【参考方案3】:如果您从 C# 8 启用最新的 Nullable 功能,也会出现这种异常。
EF Core,至少目前,它与 C# 8 可空类型不完全兼容。 例如,假设您为项目启用了 Nullable 功能,如果您有这样的类型:
public class MyEntity
public string MyProperty get; set;
即使它的属性没有标有 [Required] 属性,EF 核心也会引发这种异常,因为它要求数据库中的值不为空(即它不使用 IsDbNull 测试列值)。
有关如何在 EF 核心中处理可为空的引用类型的更多信息,请查看: https://docs.microsoft.com/en-us/ef/core/miscellaneous/nullable-reference-types
【讨论】:
简而言之:使用 C# 8,MyProperty 需要是字符串吗?如果它在数据库中是一个可为空的值。【参考方案4】:要解决 Data is Null
异常的类似问题,我必须明确地将 IsRequired(false)
放在我的列映射上。在我的例子中,我正在映射一个数据库视图。
builder.Property(x => x.MyProperty).IsRequired(false);
【讨论】:
这样做表明,因为对我来说有问题的列是复合键的一部分,所以它被 EF 自动标记为需要,这导致了问题。这并没有解决问题,但它揭示了它。TVM 我必须将类型字符串更改为字符串?【参考方案5】:解决方案:是的,错误“SqlNullValueException: Data is Null”。当模型将导致问题的字段标记为 [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 可以有一个司机(或者我称之为 Usuario),但是一个 Driver 可以有多个路由,这使得一对多的关系如下:
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] 属性。因此,我们将无法删除用户(或驱动程序)表中的记录。另外,如果数据库中已经有数据,在这种情况下,UsuarioId 为 NULL 的 Routes,它会立即显示错误。
记住,重点是:我们希望 [Required] 仅用于验证目的,因为我们可能有尚未分配给驱动程序 (UserId) 的路线,所以在数据库,它应该被允许为 NULL,而不是我们的 mvc 形式。
要解决此问题,请将字段标记为 [required],然后转到您使用 fluent API 定义关系的 DbContext 类,并像这样指定该列不是必需的:
modelBuilder.Entity<Route>()
.Property(p => p.UsuarioId).IsRequired(required: false);
所以现在注释模式下需要该字段,但最终将用于构建数据库的 fluent API 不需要该字段。这将解决问题!
【讨论】:
感谢您的回答,这真是太棒了!【参考方案6】: public bool Isgstvailable get; set;
检查 sql 视图或表中的位列。如果它返回 null ,c# 阅读器将无法读取并抛出 null ref 异常。
gst.Isgstvailable 为 null 然后强制转换(0 作为位)的情况 否则 gst.Isgstvailable 以 Isgstvailable 结尾
【讨论】:
这似乎与问题无关。此外,如果确实如此,这如何显着增加现有答案的内容? 谢谢@GertArnold,在实体框架中加载数据时,它会与模型进行映射。如果有效负载数据与数据类型不匹配,则抛出异常。我有一种情况,我在 DB 中有位字段,不幸的是它插入了空数据。在加载位字段实体框架时抛出空引用异常,由于数据类型和加载的数据类型不匹配。 是的,Ivan 已经充分解释了这一点。您的回答没有添加任何新内容。此外,它不是抛出空引用异常。【参考方案7】:只是想在这里发布;
这里的解决方案很棒,但是在我的情况下它不起作用。我使用的是 SQL 视图而不是表,并且我的所有字段都没有在模型中标记为 [Required]。
经过一番故障排除后,我发现问题出在我的整数列为空。我只是将模型中的 int 列更改为字符串(我需要此信息仅用于显示目的),它就成功了。
来自
public int BatchId get; set;
到
public string BatchId get; set;
我希望这对某人有所帮助。感谢以上所有答案!
【讨论】:
您好 Asif,我遇到了同样的问题。在我的情况下,最好从“int”更改为“int?”允许为空。数据库中的相应列也允许空值。它对你有用的原因是因为字符串总是可以为空的。【参考方案8】:[使用 isRequired()][1] 我通过在 db 上下文(由 scafford 生成)中定义表的所有属性来解决我的问题,这是否需要。
【讨论】:
【参考方案9】:不是 OP 的情况,但这也可能与关系中的倒置主键 外键配置有关。
例如:
entity
.HasOne(e => e.Principal)
.WithOne(e => e.Dependent)
.HasForeignKey<Principal>(e => e.Key) <- This should be the dependent entity
.HasPrincipalKey<Dependent>(e => e.Key); <- This should be the principal entity
而不是
entity
.HasOne(e => e.Principal)
.WithOne(e => e.Dependent)
.HasForeignKey<Dependent>(e => e.Key)
.HasPrincipalKey<Principal>(e => e.Key);
【讨论】:
以上是关于Entity Framework Core: `SqlNullValueException: Data is Null.` 如何排查?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Entity Framework Core 正确保存 DateTime?
如何使用 Entity Framework Core 在一种方法中保存两次更改
Entity Framework Core 6.0 预览4 性能改进
EF6 System.Data.Entity.Core.EntityKey 在 Entity Framework Core 中的等价物是啥?