Entity Framework Core 5 tries to insert value for computed column

1k views Asked by At

Using Entity Framework 5 and EF Core Power Tools (whith the setting to generate ef 5 code enabled) we get something like the following code generated for each computed column:

...HasComputedColumnSql("([LastName]+isnull(' '+[FirstName],''))", true);

which is perfectly right.

Unfortunately, trying to create a new entity that has computed columns and trying to save we get the following exception from ef core 5:

The column '...' cannot be modified because it is either a computed column or is the result of a UNION operator

When manualy appending the ValueGeneratedOnAddOrUpdate after the HasComputedColumnSql like so:

 ...HasComputedColumnSql("([LastName]+isnull(' '+[FirstName],''))", true).ValueGeneratedOnAddOrUpdate();

everything works fine.

According to the docs this should be automatically be called by HasComputedColumnSql.

What can be done to overcome this issue ?

We are using Microsoft.EntityFrameworkCore v5.0.5 package and also we are using an Azure Managed Sql Server Instance

1

There are 1 answers

0
idilov On

The OP already pointed out the solution: in EF core 5, when scaffolding is used, you have to manually add ValueGeneratedOnAddOrUpdate(). This problem has been fixed in EF core 6.

The patch has been mentioned in earlier answers. This answer elaborates on how to remove manual code from generated code.

Let's say the scaffolded file GenDbContext.cs contains:

modelBuilder.Entity<MyEntity>(entity =>
{
    entity.Property(e => e.ComputedName).HasMaxLength(100).IsUnicode(false)
        .HasComputedColumnSql("([LastName]+isnull(' '+[FirstName],''))", true);
});

There are two options: partial class or inheritance.

A) Partial class in GenDbContext.Extension.cs - requires EF core 3.1+

public partial class GenDbContext : DbContext
{
    partial void OnModelCreatingPartial(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<MyEntity>(entity =>
            entity.Property(e => e.ComputedName).ValueGeneratedOnAddOrUpdate()
        );
    }
}

B) Subclass in InheritedDbContext.cs.

public class InheritedDbContext : GenDbContext
{
    public InheritedDbContext(DbContextOptions<GenDbContext> options) : base(options) {}

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        modelBuilder.Entity<MyEntity>(entity =>
            entity.Property(e => e.ComputedName).ValueGeneratedOnAddOrUpdate()
        );
    }
}

Then in Startup.cs:

// The first line is still necessary as it declares DbContextOptions<GenDbContext>.
services.AddDbContext<GenDbContext>(...options...);
services.AddDbContext<InheritedDbContext>(...same options...);

There is no need to repeat the rest of the column settings such as HasMaxLength, IsUnicode and HasComputedColumnSql.