I switched form .NET 6 to .NET 7 to make use of the polymorphic serialization with System.Text.Json
.
In WebApi, serializing and deserializing works like a charm using these types:
[JsonDerivedType(typeof(FileMessageData), typeDiscriminator: nameof(FileMessageData))]
public class FileMessageData : MessageData
{
public string FileName { get; set; }
}
[JsonPolymorphic]
[JsonDerivedType(typeof(FileMessageData), typeDiscriminator: nameof(FileMessageData))]
public class MessageData
{
public string InCommon { get; set; }
}
But when it comes to EF Core 7, I wanted to use the Json Column feature. In an entity called MessageEntity
I added a property named Data
with the base type MessageData
and this configuration:
builder.OwnsOne(e => e.Data, ownedNavigationBuilder =>
{
ownedNavigationBuilder.ToJson();
});
Now my expectation is, when I assign a FileMessageData
object to the Data
property that the saved value will be
{
"$type": "FileMessageData",
"inCommon": "test",
"fileName": "hellokitty.png"
}
But unfortunately it is always an empty object:
{}
When I change the type of the Data
property on the entity to FileMessageData
, the value in the database is:
{
"inCommon": "test",
"fileName": "hellokitty.png"
}
No type discriminator
As a workaround, I'm doing this:
var options = new JsonSerializerOptions(JsonSerializerDefaults.General);
builder
.Property(e => e.Data)
.HasColumnType("nvarchar")
.HasMaxLength(4000)
.HasConversion(
v => JsonSerializer.Serialize(v, options),
s => JsonSerializer.Deserialize<MessageData>(s, options)!,
ValueComparer.CreateDefault(typeof(MessageData), true)
);
...but this doesn't allow me to query on the "InCommon" field with server evaluation because this can't obviously be translated to a query.
System.InvalidOperationException: 'The LINQ expression 'DbSet<MessageEntity>()
.Where(m => m.Data.InCommon == "HoHo")' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'. See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.'
How can I tell EF Core 7 to serialize/deserialize the object using the polymorphic JSON feature?