FirebirdSQL / NETProvider

Firebird ADO.NET Data Provider
https://www.firebirdsql.org/en/net-provider/
Other
152 stars 62 forks source link

Reload Database Generated Key Field on Insert #1163

Closed rainerbiz closed 3 months ago

rainerbiz commented 3 months ago

Hey,

I am trying to get the functionality of DatabaseGeneratedOption.Computed on a Key Column. The primary key of the table is a string which is getting changed in a Before Insert Trigger in the database. If my field is not a key and I use DatabaseGeneratedOption.Computed, everything works as I want and the value will be updated with a Returning in the query. But I cannot use this option on a key field, cause of the ValueGeneratedOnUpdate, which cannot be used for a key column. So then I tried the DatabaseGeneratedOption.Identity which only adds the ValueGeneratedOnAdd. But the DatabaseGeneratedOption.Identity Options generates a GUID for the field, which I don’t want. Then I replaced the ValueGenerator with a new Generator that leaves the field as an empty string. But then the Returning command will not be added in the Insert Query.

Is there currently no option to make the DatabaseGeneratedOption.Computed functionality work on a ValueGeneratedOnAdd key field? I also tried arround with UseIdentityColumn and UseSequenceTrigger. I just want to fill my field with an empty string and let it update after the insert using a returning command.

I am sorry if this question is wrong here, but I tried everything and looked through the code, but I could not find a solution to my problem.

cincuranet commented 3 months ago

You need to make sure the locally generated value is marked as temporary. Easiest is probably to take the default StringValueGenerator and override GeneratesTemporaryValues.

Here's an example.

class MyContext : DbContext
{
    public DbSet<TEST> TEST { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        base.OnConfiguring(optionsBuilder);

        optionsBuilder.UseFirebird("...");
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        modelBuilder.Entity<TEST>(b =>
        {
            b.Property(x => x.ID)
                .ValueGeneratedOnAdd()
                .HasValueGenerator<MyStringKeyGenerator>();
        });
    }
}

class TEST
{
    public string ID { get; set; }
    public double? FOO { get; set; }
}

class MyStringKeyGenerator : StringValueGenerator
{
    public override bool GeneratesTemporaryValues => true;
}
rainerbiz commented 3 months ago

Thank you very much! I totally ignored the GeneratesTemporaryValues and did not think much about it, when i tried around with a custom generator. Now it works perfectly!