EF Npgsql Core not generating temporary Id on Insert

c# entity-framework-core npgsql postgresql

Question

Recently I've migrated from EF Npgsql Core 2.2 to the 3.1.1. All good, but now when using Add or AddRange methods from EF, a temporary Id isn't being sett on my entity.

Does anyone knows what can be the reason? Usually when I called add, a id value was sett with some random value like -1245343. I also tried to put the ValueGeneratedOnAdd for that table but no luck.

I'm going to put here the definition of a entity class, my DbContext, DI configuration for the DbContext, as well as the SQL script of the table.

The Entity

 public class StatementHeader : RFBaseEntity
    {
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public virtual int Id { get; set; }
        public double TotalLocal { get; set; }
        public double TotalForeign { get; set; }

        .....
    }

The DBContext

public abstract class EFBaseContext : DbContext
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="EFBaseContext"/> class.
        /// Do not use for test only
        /// </summary>
        protected EFBaseContext()
        {
        }

        protected EFBaseContext(DbContextOptions options) : base(options)
        {
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.RemovePluralizingTableNameConvention();
            modelBuilder.Entity<Source>()
                .HasMany(x => x.Templates)
                .WithOne(x => x.Source);
            modelBuilder.Entity<StatementHeader>()
                .Property(i => i.Id)
                .ValueGeneratedOnAdd();

            modelBuilder.UseSerialColumns();
            modelBuilder.RemoveCascadeDeleteConvention();
            modelBuilder.HasDefaultSchema("public");

                base.OnModelCreating(modelBuilder);
            }
}

The Autofac DI container

 var dbContextOptionsBuilder = new DbContextOptionsBuilder<EFCoreContext>()
                .UseNpgsql(WebApiConfigurations.ConnectionString, (x=>x.SetPostgresVersion(9,6)));

            builder.RegisterType<EFCoreContext>().As<DbContext>().WithParameter("options", dbContextOptionsBuilder.Options)
                .InstancePerLifetimeScope();

Table Definition

CREATE TABLE public."StatementHeader" (
    "Id" serial NOT NULL,
    "CreatedOn" timestamp without time zone NOT NULL,
    "ModifiedOn" timestamp without time zone NULL,
    "CreatedByUserLogin" text NULL,
    "ModifiedByUserLogin" text NULL,
    "Description" text NULL,
    "TotalLocal" double precision NOT NULL,
    "TotalForeign" double precision NOT NULL,
    "Date" timestamp without time zone NOT NULL,
    "Comments" text NULL,
    "TemplateId" integer NOT NULL,
    "PaymentReceivedId" integer NULL,
    CONSTRAINT "PK_StatementHeader" PRIMARY KEY ("Id"),
    CONSTRAINT "FK_StatementHeader_PaymentReceived_PaymentReceivedId" FOREIGN KEY ("PaymentReceivedId") REFERENCES public."PaymentReceived" ("Id") ON DELETE RESTRICT,
    CONSTRAINT "FK_StatementHeader_Template_TemplateId" FOREIGN KEY ("TemplateId") REFERENCES public."Template" ("Id") ON DELETE RESTRICT
);
1
1
4/4/2020 12:40:16 AM

Accepted Answer

This behavior was expected in 3.0?

Yes, it is one of the 3.0 Breaking Changes - Temporary key values are no longer set onto entity instances.

The proposed solutions there are:

  • Not using store-generated keys.
  • Setting navigation properties to form relationships instead of setting foreign key values.
  • Obtain the actual temporary key values from the entity's tracking information. For example, context.Entry(blog).Property(e => e.Id).CurrentValue will return the temporary value even though blog.Id itself hasn't been set.

Option #1 doesn't make sense (apparently the affected places already use store generated keys).

Option #2 is preferable if you have navigation properties.

Option #3 is closer to the previous behavior, but requires access to the db context.

2
9/28/2019 2:13:50 PM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow