DbContext tries to save nonzero fields as null

I have two projects

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

I do not want to bind StoreSku.Datato any particular provider, so I moved this feature to StoreSku.Provider. I am creating a model and parameters in StoreSku.Providerand passing parameters to DbContext, using the following code:

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;

As you can see, this is pretty verbose. Whether I need all these calls is another question. My question is more focused in the following areas:

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

The error that I encountered is that if I do not have these lines, I get the following errors:

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.

Schema for this table

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

And model

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; }
}

And the calling code:

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

    Context.SaveChanges();
}

And the generated SQL command

BEGIN TRANSACTION

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

ROLLBACK TRANSACTION 

Why do I need to specify ValueGeneratedNever();for each of these properties? Why is EFCore trying to save them as null?

+4
1

, https://github.com/aspnet/EntityFramework/issues/3529

, ModelBuilder, .. (, "" ).

( , Create() factory, ctor, factory, ctor DI)

var builder = SqlServerModelBuilderFactory.Create()

, , DI, , ... .., DI (, mapper .., ).

sp.AddEntityFramework() .AddSqlCompact() .AddNpgSql() .AddSqlServer();

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

SqlServerModelBuilderFactory, , SqlServerConventionSetBuilder; .

,

var conventions = new ConventionSet();

var conventions = SqlServerConventionSetBuilder.Build();

.

+1

Source: https://habr.com/ru/post/1682270/


All Articles