-
Notifications
You must be signed in to change notification settings - Fork 3.3k
Open
Labels
Description
Bug description
When two subclasses are stored in the same table using TPH, all columns mapped from properties that are exclusive to one of the subclasses will be marked as nullable, becuase if the row is an instance of the 'other' subclass that column will not have a value. Except for complex properties stored as json. This leads to exceptions when storing data because the database expect a value where there is none. This issue does not exist when using owned entities instead of complex entities.
Workaround is to explicitly specifiy IsRequired(false) but that doesn't seem the intended solution.
Your code
using System.Diagnostics;
using Microsoft.EntityFrameworkCore;
const string connectionString = "Server=localhost;Database=complex-issues;Port=5432;User Id=postgres;Password=postgres;Include Error Detail=true";
var options = new DbContextOptionsBuilder<AppDbContext>()
.UseNpgsql(connectionString)
.Options;
var dbContext = new AppDbContext(options);
await dbContext.Database.EnsureDeletedAsync();
await dbContext.Database.EnsureCreatedAsync();
var entity = new EntityWithoutComplexJson();
dbContext.Entities.Add(entity);
await dbContext.SaveChangesAsync();
public abstract class Entity
{
public Guid Id { get; init; }
}
public class EntityWithoutComplexJson : Entity
{
}
public class EntityWithComplexJson : Entity
{
public required ComplexEntity ComplexEntity { get; init; }
}
public class ComplexEntity
{
public required string Value { get; init; }
}
public class AppDbContext(DbContextOptions options) : DbContext(options)
{
public DbSet<Entity> Entities { get; init; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<EntityWithoutComplexJson>();
modelBuilder.Entity<EntityWithComplexJson>().ComplexProperty(entity => entity.ComplexEntity).ToJson();
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
base.OnConfiguring(optionsBuilder);
optionsBuilder.LogTo(message =>
{
Debug.WriteLine(message);
});
}
}Stack traces
---> Npgsql.PostgresException (0x80004005): 23502: null value in column "ComplexEntity" of relation "Entities" violates not-null constraint
DETAIL: Failing row contains (019b373e-f53a-7786-ac07-94575699cf3c, EntityWithoutComplexJson, null).
at Npgsql.Internal.NpgsqlConnector.ReadMessageLong(Boolean async, DataRowLoadingMode dataRowLoadingMode, Boolean readingNotifications, Boolean isReadingPrependedMessage)
at System.Runtime.CompilerServices.PoolingAsyncValueTaskMethodBuilder`1.StateMachineBox`1.System.Threading.Tasks.Sources.IValueTaskSource<TResult>.GetResult(Int16 token)
at Npgsql.NpgsqlDataReader.NextResult(Boolean async, Boolean isConsuming, CancellationToken cancellationToken)
at Npgsql.NpgsqlDataReader.NextResult(Boolean async, Boolean isConsuming, CancellationToken cancellationToken)
at Npgsql.NpgsqlCommand.ExecuteReader(Boolean async, CommandBehavior behavior, CancellationToken cancellationToken)
at Npgsql.NpgsqlCommand.ExecuteReader(Boolean async, CommandBehavior behavior, CancellationToken cancellationToken)
at Npgsql.NpgsqlCommand.ExecuteDbDataReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
Exception data:
Severity: ERROR
SqlState: 23502
MessageText: null value in column "ComplexEntity" of relation "Entities" violates not-null constraint
Detail: Failing row contains (019b373e-f53a-7786-ac07-94575699cf3c, EntityWithoutComplexJson, null).
SchemaName: public
TableName: Entities
ColumnName: ComplexEntity
File: execMain.c
Line: 1947
Routine: ExecConstraints
--- End of inner exception stack trace ---
Verbose output
EF Core version
10.0.1
Database provider
Npgsql.EntityFrameworkCore.PostgreSQL
Target framework
.NET 10.0
Operating system
MacOS
IDE
Rider