-
Notifications
You must be signed in to change notification settings - Fork 3.4k
Description
Bug description
Tried to migrate OwnsOne(...). to an optional complex property, since #31376 fixed that.
It seems that default values for properties within the containing complex type are treated as unchanged, when the containing complex type was null before. I first observed this in actual application code for bool properties, but could reproduce it for DateTimeOffset as well.
The target SQL table shows a null value for the default-valued properties, so it's not an issue with materializing those on load.
Also complex types with more than one property are affected as well, I just used a one-property type for brevity. The main difference I could observe is, that for types with exactly one property on the complex type, the containing complex property would materialize to null on load, while for types with more than one property it would get created.
I haven't tried for types with multiple default-valued properties, though.
Your code
#:package Microsoft.EntityFrameworkCore.SqlServer@10.0.1
#:property PublishAot=false
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
await using var context = new UserContext();
await context.Database.EnsureDeletedAsync();
await context.Database.EnsureCreatedAsync();
var entity = new User()
{
LockInfo = null
};
context.Users.Add(entity);
await context.SaveChangesAsync();
await LoadAndPrintLockInfo();
await LockUser(default(DateTimeOffset));
await LoadAndPrintLockInfo(); //Expectation would be "01.01.0001", actually is "null"
await LockUser(DateTimeOffset.Now.AddDays(30));
await LoadAndPrintLockInfo();
async Task LockUser(DateTimeOffset until)
{
context.ChangeTracker.Clear();
var user = await context.Users.SingleAsync();
user.LockInfo = new(until);
await context.SaveChangesAsync();
}
async Task LoadAndPrintLockInfo()
{
context.ChangeTracker.Clear();
var user = await context.Users.SingleAsync();
Console.WriteLine("Currently locked until: " + (user.LockInfo?.LockedUntil.ToString() ?? "null"));
}
public class UserContext : DbContext
{
public DbSet<User> Users { get; set; } = null!;
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.UseSqlServer("Server=(localdb)\\MSSQLLocalDB;Initial Catalog=DefaultPropertyRepro;Integrated Security=true");
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
var user = modelBuilder.Entity<User>();
user.HasKey(p => p.Id);
user.ComplexProperty(u => u.LockInfo).Property(p => p.LockedUntil);
}
}
public class User
{
public int Id { get; set; }
public LockInfo? LockInfo { get; set; }
}
public record LockInfo(DateTimeOffset LockedUntil);Stack traces
Verbose output
EF Core version
10.0.1
Database provider
Microsoft.EntityFrameworkCore.SqlServer
Target framework
.NET 10
Operating system
Windows 11
IDE
Visual Studio 2026