Using runtime-evaluated expressions (e.g., DateTime.UtcNow, Guid.NewGuid()) as default values for a property causes the
value to be hardcoded as a static value in the database schema, rather than computed per row. This affects HasDefaultValue() in Fluent
API configurations and defaultValue in migration files.
Why is this an issue?
- The Cause: These C# expressions evaluate once when the model builds or the migration runs, rather than dynamically by the database.
- The Result: Every new record receives that exact same static value — the same timestamp, or the same GUID — instead of a value computed at insertion time.
Starting with EF Core 9, this also throws an InvalidOperationException for the PendingModelChangesWarning warning when
applying migrations, because the default value expression evaluates to a new value on each model build, making migrations non-deterministic.
How to fix it
Replace HasDefaultValue() with HasDefaultValueSql() in Fluent API configurations, and replace defaultValue
with defaultValueSql in migration files. This instructs EF Core to let the database engine generate the value at insertion time, using
the equivalent function for your database provider:
| Client-evaluated expression | SQL Server | PostgreSQL | MySQL / MariaDB | SQLite | Oracle |
|---|---|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(no offset-aware type; closest is |
(no offset-aware type) |
|
|
|
|
|
|
|
|
|
|
|
|
|
(no native function) |
|
|
|
(no native function) |
|
|
(no native function) |
(no native function) |
Some provider-specific quirks to be aware of when picking a replacement:
- MySQL’s
UUID()returns a version 1 UUID, not version 4; MariaDB additionally provides a dedicatedUUID_v4(). - Oracle’s
SYS_GUID()returns a raw 16-byte value, not formatted as a standard hyphenated UUID string. - SQLite has no native UUID generation function of any version; generate the value in application code instead.
- SQLite and Oracle have no time-zone-aware temporal type, so
DateTimeOffsetvalues don’t map cleanly to a single database type.
Code examples
Noncompliant code example
public void Configure(EntityTypeBuilder<Student> builder)
{
builder.HasKey(x => x.StudentId);
builder.Property(x => x.EnrollmentDate)
.IsRequired(true)
.HasDefaultValue(DateTime.Now); // Noncompliant
}
Compliant solution
public void Configure(EntityTypeBuilder<Student> builder)
{
builder.HasKey(x => x.StudentId);
builder.Property(x => x.EnrollmentDate)
.IsRequired(true)
.HasDefaultValueSql("GETDATE()"); // SQL Server example — see the table above for other providers
}
Noncompliant code example
migrationBuilder.AddColumn<DateTime>(
name: "EnrollmentDate",
table: "Students",
nullable: false,
defaultValue: DateTime.UtcNow); // Noncompliant
Compliant solution
migrationBuilder.AddColumn<DateTime>(
name: "EnrollmentDate",
table: "Students",
nullable: false,
defaultValueSql: "GETUTCDATE()"); // SQL Server example — see the table above for other providers
Noncompliant code example
public void Configure(EntityTypeBuilder<Student> builder)
{
builder.HasKey(x => x.StudentId);
builder.Property(x => x.TranscriptId)
.HasDefaultValue(Guid.NewGuid()); // Noncompliant
}
Compliant solution
public void Configure(EntityTypeBuilder<Student> builder)
{
builder.HasKey(x => x.StudentId);
builder.Property(x => x.TranscriptId)
.HasDefaultValueSql("NEWID()"); // SQL Server example — see the table above for other providers
}
Resources
Documentation
- Microsoft Learn - Entity Framework Core - Default Values
- Microsoft Learn - Date/time value generation
- Microsoft Learn - SQL Server GETDATE() Function
- Microsoft Learn - EF Core 9 - Pending model changes