我在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);
}
跟踪
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" />
答案 0 :(得分:4)
如果从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
答案 1 :(得分:3)
要解决Data is Null
异常的类似问题,我必须在列映射中显式放置IsRequired(false)
。就我而言,我正在映射数据库视图。
builder.Property(x => x.MyProperty).IsRequired(false);
答案 2 :(得分:2)
错误消息表明EF Core正在尝试读取必需属性的string
值,即从不应该具有{{1} }数据库中的值,但是底层数据读取器在某些记录中报告null
该属性的值{s)。
通过查看实体模型和相应的数据库表,您可以看到许多null
属性-> string
列之间明显的差异。 varchar
,CompanyStreetAddress
,CompanyCity
,CompanyZipCode
,CompanyVatNumber
,ContactFirstName
-在模型中所有这些都标记为ContactLastName
,表中没有相应的[Required]
约束。
因此,问题是由这些列中的一个或多个引起的。
您需要解决该差异-可能是通过删除not null
属性,因为现有数据中的约束已被破坏。
它在某些较旧的EF Core版本中“起作用”的事实并不重要-这是不正确的映射,因此应予以修复。从技术上讲,它不应该从一开始就起作用。但是请记住,EF Core仍在积极开发中,并且存在许多错误,这些错误已在下一版本中修复。很有可能在“正常”和“无效” EF Core版本之间进行了一些代码更改,该版本修复了以前的不正确行为。
答案 3 :(得分: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; }
}
注意:这不是原始问题的答案,而是标题中问题的答案。
答案 4 :(得分:1)
解决方案:是,错误“ SqlNullValueException:数据为空”。当模型将字段标记为引起问题的字段为[必需]时,导致(表的)列中的值为NULL,这是很容易解决的。使用数字字段可以轻松解决此问题,但是当字段为字符串类型时,这确实很糟糕。
考虑以下两个使用分发路由示例的类,每个路由都有一个驱动程序,当然,每个驱动程序都有一个或多个路由。
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>();
}
您可能会猜到,一个路线可以有一个驱动程序(或我所说的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);
}
根据FluentAPI,当删除驱动程序时,其行为是将UsuarioId字段(在Routes模型中)设置为NULL,但这违反了[Required]属性。因此,我们将无法删除“用户(或驱动程序)”表中的记录。另外,如果数据库中已经有数据(在这种情况下为NULL为UsuarioId的Routes),它将立即显示错误。
请记住,重点是:我们希望[Required]仅用于验证目的,因为我们可能尚未将路由分配给驱动程序(UserId),因此在数据库中,应将其设置为NULL,而不是我们的mvc形式。
要解决此问题,请将字段标记为[required],然后转到您使用fluent API定义关系的DbContext类,并指定不需要该列,如下所示:
modelBuilder.Entity<Route>()
.Property(p => p.UsuarioId).IsRequired(required: false);
因此该字段现在在注释模式下是必需的,但最终将用于构建数据库的fluent API不需要该字段。这样可以解决问题!
答案 5 :(得分:1)
只是想把这个贴在这里;
这里的解决方案很棒,但在我的情况下不起作用。我使用的是 SQL 视图而不是表,并且模型中的所有字段都没有标记 [Required]。
经过一些故障排除后,我发现问题来自我的整数列为空。我只是将模型中的 int 列更改为字符串(我需要此信息仅用于显示目的),它就成功了。
来自
public int BatchId { get; set; }
到
public string BatchId { get; set; }
我希望这对某人有所帮助。感谢以上所有回答!
答案 6 :(得分:0)
不是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);
答案 7 :(得分:-1)
public bool Isgstvailable { get; set; }
检查sql视图或表中的bit列。如果返回null,则c#读者无法读取并引发null ref异常。
当gst.Isgstvailable为null时,然后强制转换(位为0) 其他gst.Isgstvailable结尾为Isgstvailable