微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

c# – DbContext尝试将非空字段保存为null

我有两个项目

StoreSku.Data - Depends On: Microsoft.EntityFrameworkCore
StoreSku.Provider - Depends On: StoreSku.Data,Microsoft.EntityFrameworkCore.sqlServer

我不想将StoreSku.Data绑定到任何特定的提供程序,因此我将该可重用性转移到StoreSku.Provider.我正在StoreSku.Provider中创建模型和选项,并使用以下代码将选项传递到DbContext:

var optionsBuilder = new DbContextOptionsBuilder();
optionsBuilder.UsesqlServer(connectionString);

var conventions = new ConventionSet();
var modelBuilder = new ModelBuilder(conventions);

modelBuilder.Entity<StoreSkuUpdateRequest>().HasKey(request => request.Id);
modelBuilder.Entity<StoreSkuUpdateRequest>().Property(request => request.Id).UsesqlServerIdentityColumn();
modelBuilder.Entity<StoreSkuUpdateRequest>().Property(request => request.StoreNumber).ValueGeneratednever();
modelBuilder.Entity<StoreSkuUpdateRequest>().Property(request => request.BusinessDate).ValueGeneratednever();
modelBuilder.Entity<StoreSkuUpdateRequest>().Property(request => request.Timestamp).ValueGeneratednever();
modelBuilder.Entity<StoreSkuUpdateRequest>().HasMany(request => request.RequestedUpdates).WithOne(update => update.UpdateRequest);
modelBuilder.Entity<StoreSkuUpdateRequest>().HasMany(request => request.RelatedUpdates).WithOne(relatedUpdate => relatedUpdate.UpdateRequest);
modelBuilder.Entity<StoreSkuUpdateRequest>().ForsqlServerToTable("StoreSkuUpdateRequest");

modelBuilder.Entity<StoreSkuAvailabilityUpdate>().HasOne(update => update.UpdateRequest).WithMany(request => request.RequestedUpdates);
modelBuilder.Entity<StoreSkuAvailabilityUpdate>().HasMany(update => update.RelatedUpdates).WithOne(relatedUpdate => relatedUpdate.RequestedUpdate);
modelBuilder.Entity<StoreSkuAvailabilityUpdate>().ForsqlServerToTable("RequestedStoreSkuUpdate");

modelBuilder.Entity<RelatedStoreSkuUpdate>().HasOne(relatedUpdate => relatedUpdate.RequestedUpdate).WithMany(update => update.RelatedUpdates);
modelBuilder.Entity<RelatedStoreSkuUpdate>().HasOne(relatedUpdate => relatedUpdate.UpdateRequest).WithMany(request => request.RelatedUpdates);
modelBuilder.Entity<RelatedStoreSkuUpdate>().ForsqlServerToTable("RelatedStoreSkuUpdate");

optionsBuilder.UseModel(modelBuilder.Model);

DbContextOptions options = optionsBuilder.Options;

正如你所看到的,它非常冗长.我是否需要所有这些电话是一个不同的问题.我的问题更侧重于以下几点:

modelBuilder.Entity<StoreSkuUpdateRequest>().Property(request => request.StoreNumber).ValueGeneratednever();
modelBuilder.Entity<StoreSkuUpdateRequest>().Property(request => request.BusinessDate).ValueGeneratednever();
modelBuilder.Entity<StoreSkuUpdateRequest>().Property(request => request.Timestamp).ValueGeneratednever();

我遇到的错误是,如果我没有这些行,我会收到以下错误

Cannot insert the value NULL into column 'StoreNumber',table 'dbo.StoreSkuUpdateRequest'; column does not allow nulls. INSERT fails.
The statement has been terminated.
Cannot insert the value NULL into column 'BusinessDate',table 'dbo.StoreSkuUpdateRequest'; column does not allow nulls. INSERT fails.
The statement has been terminated.
Cannot insert the value NULL into column 'Timestamp',table 'dbo.StoreSkuUpdateRequest'; column does not allow nulls. INSERT fails.
The statement has been terminated.

该表的架构是

CREATE TABLE [dbo].[StoreSkuUpdateRequest](
[Id] [bigint] IDENTITY(1,1) NOT NULL,[StoreNumber] [int] NOT NULL,[BusinessDate] [date] NOT NULL,[Timestamp] [datetime] NOT NULL)

和模型

public sealed class StoreSkuUpdateRequest
{
    [required]
    public long Id { get; set; }

    [required]
    public int StoreNumber { get; set; }

    [required]
    public DateTime BusinessDate { get; set; }

    [required]
    public DateTime Timestamp { get; set; }
}

调用代码

using (Context)
{
    var request = new StoreSkuUpdateRequest
    {
        StoreNumber = 12345,BusinessDate = DateTime.UtcNow,Timestamp = DateTime.UtcNow
    };
    Context.StoreSkuAvailabilityUpdateRequests.Add(request);

    Context.SaveChanges();
}

并且生成sql命令是

BEGIN TRANSACTION

SET NOCOUNT ON;
INSERT INTO [StoreSkuUpdateRequest]
DEFAULT VALUES;
SELECT [Id]
FROM [StoreSkuUpdateRequest]
WHERE @@ROWCOUNT = 1 AND [Id] = scope_identity();

ROLLBACK TRANSACTION

为什么我必须指定ValueGeneratednever();对于这些属性中的每一个?为什么EFCore试图将它们保存为null?

解决方法

根据Ivan Stoev在原帖中的评论,我偶然发现了 https://github.com/aspnet/EntityFramework/issues/3529的这一点

discussed in triage and decided we should have ModelBuilder factories so that folks don’t need to worry about conventions etc. (especially since conventions are ‘internal’ for the first release).

Folks can just create one up like this (note this is a static Create() method on the factory rather than a default ctor to get a factory since having a default ctor doesn’t play well with DI):

var builder = sqlServerModelBuilderFactory.Create()

Alternatively,if you want it to get all it’s services from DI then we’ll register one that you can just resolve… then you will get the same logger,etc. that is registered in DI (plus if you have overridden the type mapper etc. then you will also get those services).

sp.AddEntityFramework()
.AddsqlCompact()
.AddNpgsql()
.AddsqlServer()
;

var builder = sp.GetService<IsqlServerModelBuilderFactory>().Create();

我无法找到sqlServerModelBuilderFactory类,这导致我调查是否有sqlServerConventionSetBuilder;有.

所以改变它

var conventions = new ConventionSet();

var conventions = sqlServerConventionSetBuilder.Build();

修正了我.

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐