Entity Framework Core: `SqlNullValueException: данные пустые. Как устранить неполадки? - PullRequest
1 голос
/ 27 апреля 2019

Я использую Entity Framework Core в приложении ASP.NET Core и действии Controller, и я не изменил что-то ни в рабочем коде, ни в базе данных, но я не могу сказать, какой запрос выполняет 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, чтобы сделать это вручную, чтобы я мог попытаться выяснить, что не так с запросом.

Мне интересно, что, возможно, могло случиться. Тем более что другие объекты, такие как пользователь или страны, все еще могут быть получены из базы данных.

Есть идеи, как устранить неполадку, лежащую в основе?

[EDIT]

Единственное, что на самом деле изменилось в «коде», это ссылки на 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" />

1 Ответ

2 голосов
/ 28 апреля 2019

Сообщение об ошибке указывает, что EF Core пытается прочитать string значение для обязательного свойства, т. Е. Свойства, которое никогда не имеет null значения в базе данных, но вместо этого базовый считыватель данных сообщает null значение для этого свойства в некоторых записях.

Глядя на вашу модель сущности и соответствующую таблицу базы данных, вы можете увидеть очевидное несоответствие для многих string свойств -> varchar столбцов. CompanyStreetAddress, CompanyCity, CompanyZipCode, CompanyVatNumber, ContactFirstName, ContactLastName - все они помечены как [Required] в модели, бит не имеет соответствующего ограничения not null в таблице.

Таким образом, проблема вызвана одним или несколькими из этих столбцов.

Необходимо устранить это несоответствие - возможно, удалив атрибут [Required], поскольку ограничение уже нарушено в существующих данных.

Тот факт, что он «работает» в какой-то более старой версии EF Core, не имеет значения - это неправильное отображение, и поэтому оно должно быть исправлено. Технически это не должно работать с самого начала. Но помните, что EF Core все еще находится в активной разработке и имеет много ошибок, которые будут исправлены в следующих выпусках. Скорее всего, было сделано некоторое изменение кода между «работающей» и «неработающей» версией EF Core, которая исправляет предыдущее некорректное поведение.

...