Bug description
When you have a complex or owned type stored as json, with a scalar property that has a converter that can convert null values, the converter isn't ran when the value of the scalar is null. This is both during serialization aswell as deserialization
For serialization, this causes null to be stored in the field
For deserialization, this causes null values to be retrieved
Both could cause unexpected errors.
Your code
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using System.Diagnostics;
var options = new DbContextOptionsBuilder<AAMyDbContext>()
.EnableSensitiveDataLogging()
.UseSqlServer("Server=(localdb)\\mssqllocaldb;Database=AAMyDbContext;Trusted_Connection=True;")
.LogTo(Console.WriteLine, Microsoft.Extensions.Logging.LogLevel.Information)
.Options;
using (var context = new AAMyDbContext(options))
{
await context.Database.EnsureDeletedAsync();
await context.Database.EnsureCreatedAsync();
var entity = new EntityType
{
Id = Guid.NewGuid(),
ComplexType = new ComplexType
{
Int = null, // (Fail) Should be stored as "<null>", but is stored as null. Converter hasn't ran
String = "<null>" // Correctly stored as null
}
};
context.Add(entity);
await context.SaveChangesAsync();
context.ChangeTracker.Clear();
var retrievedEntity = await context.EntityTypes.FirstAsync();
Debug.Assert(retrievedEntity.ComplexType.String == "<null>"); // Fails, retrievedEntity.ComplexType.String is null, converter hasn't ran
}
internal class AAMyDbContext(DbContextOptions<AAMyDbContext> options) : DbContext(options)
{
public DbSet<EntityType> EntityTypes => Set<EntityType>();
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
var type = modelBuilder.Entity<EntityType>();
modelBuilder.Entity<EntityType>().ComplexProperty(x => x.ComplexType, cfg =>
{
cfg.ToJson();
cfg.Property(x => x.Int).HasConversion(new NullIntToNonNullStringConverter()).IsRequired(false);
cfg.Property(x => x.String).HasConversion(new NonNullStringToNullStringConverter())
.IsRequired(false);
});
}
}
public class NullIntToNonNullStringConverter() : ValueConverter<int?, string>(
v => v == null ? "<null>" : v.ToString()!, v =>
v == "<null>" ? null : int.Parse(v))
{
public override bool ConvertsNulls => true;
}
public class NonNullStringToNullStringConverter() : ValueConverter<string, string?>(
v => v == "<null>" ? null : v, v => v ?? "<null>")
{
public override bool ConvertsNulls => true;
}
public class EntityType
{
public Guid Id { get; set; }
public ComplexType ComplexType { get; set; } = null!;
}
public class ComplexType
{
public int? Int { get; set; } = null!;
public string String { get; set; } = "<null>";
}
Stack traces
Verbose output
EF Core version
10.0.5
Database provider
Microsoft.EntityFrameworkCore.SqlServer
Target framework
.NET 10
Operating system
W11
IDE
VS2026
Bug description
When you have a complex or owned type stored as json, with a scalar property that has a converter that can convert null values, the converter isn't ran when the value of the scalar is null. This is both during serialization aswell as deserialization
For serialization, this causes null to be stored in the field
For deserialization, this causes null values to be retrieved
Both could cause unexpected errors.
Your code
Stack traces
Verbose output
EF Core version
10.0.5
Database provider
Microsoft.EntityFrameworkCore.SqlServer
Target framework
.NET 10
Operating system
W11
IDE
VS2026