dotnet / efcore

EF Core is a modern object-database mapper for .NET. It supports LINQ queries, change tracking, updates, and schema migrations.
https://docs.microsoft.com/ef/
MIT License
13.73k stars 3.18k forks source link

Scaffolding doesn't generate default values #25654

Closed cilerler closed 2 years ago

cilerler commented 3 years ago

Scaffolding doesn't generate default values, and I wonder if there is a way to enforce it. Ideally I would expect [DatabaseGenerated(DatabaseGeneratedOption.Computed)] attribute in models.

e.g.:

Source

[CreatedAt] DATETIME2 (3) CONSTRAINT [DF_importQueue_CreatedAt] DEFAULT (sysutcdatetime()) NOT NULL,
[SoftDelete] BIT CONSTRAINT [DF_importQueue_SoftDelete] DEFAULT ((1)) NOT NULL,

Actual

public DateTime CreatedAt { get; set; }
public bool SoftDelete { get; set; }

Expected

[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime CreatedAt { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public bool SoftDelete { get; set; }
// OR at least
// public bool SoftDelete { get; set; } = true;
ajcvickers commented 3 years ago

@cilerler [DatabaseGenerated(DatabaseGeneratedOption.Computed)] is only be scaffolded for computed columns, which these are not. Can you provide some more details about what it is you are trying to achieve?

cilerler commented 3 years ago

Thanks, @ajcvickers. I want the database default values to be available in the codebase.
Right now, it ignores any default values on the database, and C# assigns false to SoftDelete and DateTime.Min to CreatedAt.
The database default value only applies if the property is null, where those will never be null.
On second thought, the best solution would be scaffolding to mark the field as nullable if it has a DefaultValue on the database. So C# won't go to assign value, and it will get the default value from the server if there is no data for the field.
Is that make sense?

ajcvickers commented 3 years ago

@cilerler We have documentation on default values in change tracking. Hopefully it answers your questions.

cilerler commented 3 years ago

@ajcvickers As stated in the subject, the issue is Scaffolding doesn't generate default values. Can you elaborate on which part you think is related to the topic, please?

ajcvickers commented 3 years ago

@cilerler Default values are scaffolded into the EF model. For example:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.HasAnnotation("Relational:Collation", "SQL_Latin1_General_CP1_CI_AS");

    modelBuilder.Entity<Foo>(entity =>
    {
        entity.Property(e => e.CreatedAt)
            .HasPrecision(3)
            .HasDefaultValueSql("(sysutcdatetime())");

        entity.Property(e => e.SoftDelete)
            .IsRequired()
            .HasDefaultValueSql("((1))");
    });

    OnModelCreatingPartial(modelBuilder);
}
cilerler commented 3 years ago

@ajcvickers, are you sure? It is not the case in my scenario. Did you hand-typed those, or did you test it?

ajcvickers commented 3 years ago

@cilerler I tested it and copy-pasted the generated code into here.

cilerler commented 3 years ago

thanks for the quick reply, any idea why it may not generate it? (by the way source database is Azure SQL, if that make any difference)

ajcvickers commented 3 years ago

@cilerler Post the database schema for the tables you are scaffolding from and I'll take a look.

cilerler commented 3 years ago
CREATE TABLE [dbo].[Foo] (
   [ID]                   BIGINT        IDENTITY (1, 1) NOT NULL,
   [CreatedAt]            DATETIME2 (3) CONSTRAINT [DF_Foo_CreatedAt] DEFAULT (sysutcdatetime()) NOT NULL,
   [SoftDelete]           BIT           CONSTRAINT [DF_Foo_SoftDelete] DEFAULT ((1)) NOT NULL,
   CONSTRAINT [PK_Foo] PRIMARY KEY CLUSTERED ([ID] ASC) WITH (STATISTICS_NORECOMPUTE = ON),
);
ErikEJ commented 3 years ago

Lack of rights to the Azure SQL db, known issue.

cilerler commented 3 years ago

@ErikEJ, can you provide me a link that states the issue, please? @ajcvickers I tested with the initial admin on AzureSQL, and it worked. So clearly it is a permission issue, and I wonder what permissions it needs to retrieve DefaultValues; other than being SA, any lead appreciated.

ErikEJ commented 3 years ago

@cilerler This is the related issue (notice that I have added a check for this to EF Core Power Tools) https://github.com/dotnet/efcore/issues/22842

cilerler commented 3 years ago

bitmoji