Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Specify EF Core column/field as read only

I have a SQL Server table with certain fields that are set by the database via default values that, once saved, should never been modified again (e.g. DateCreated).

In the Entity Framework Core 2.1 model builder or classes, how do we "mark" a field as essentially read-only? In other words, I don't want any code to be able to set or overwrite these fields.

Based on my searching, would I add .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity) at the end of .Property()?

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Doohicky>(entity =>
    {
        ... // other fields

        entity.Property(e => e.DateCreated).HasDefaultValueSql("(getdate())");

        ... // other fields
    });
}

Or do I add a [DatabaseGenerated(DatabaseGeneratedOption.Identity)] annotation to the DateCreated field?

public class Doohicky
{
    public DateTime DateCreated {get; set;}
}

Or is there another way entirely?

I want it such that in the future, if anybody decides to write something like this, an error would be thrown.

model.DateCreated = new DateTime();
dbContext.SaveChanges() // errors out

Any insight would be greatly appreciated.

like image 393
noblerare Avatar asked Jan 03 '19 21:01

noblerare


2 Answers

The EF Core intended way is to set AfterSaveBehavior property to value other than the default Save:

Gets a value indicating whether or not this property can be modified after the entity is saved to the database.

If Throw, then an exception will be thrown if a new value is assigned to this property after the entity exists in the database.

If Ignore, then any modification to the property value of an entity that already exists in the database will be ignored.

There is no dedicated fluent API yet, so you need to set it directly through mutable property metadata like this:

entity.Property(e => e.DateCreated)
    .HasDefaultValueSql("(getdate())")
    .Metadata.AfterSaveBehavior = PropertySaveBehavior.Throw; // <-- 

Update (EF Core 3.x): Starting with EF Core 3.0, many properties like this have been replaced with Get / Set extension method pairs, so the relevant code now is as follows:

    .Metadata.SetAfterSaveBehavior(PropertySaveBehavior.Throw); 
like image 133
Ivan Stoev Avatar answered Nov 19 '22 18:11

Ivan Stoev


[Required, DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime DateCreated {get; set;}
like image 33
Mohamed Elrashid Avatar answered Nov 19 '22 19:11

Mohamed Elrashid