Search code examples
c#postgresqlentity-framework-coreef-code-firstnpgsql

Storing an owned entity as JSON, and managing updates to the object graph


I'm using EF Core (8.x) and Posgresql for storing some data. Specifically, I have an entity type which has a (navigation) property holding an entire object graph, that I have specified in OnModelCreating as owned and stored as JSON (in a jsonb column):

var entityBuilder = modelBuilder.Entity<OwningEntityType>();

entityBuilder.OwnsOne(c => c.OwnedNavigationProperty, b => {
    b.ToJson();
    b.OwnsMany(c => c.ListOfThings);
    b.OwnsMany(c => c.OtherListOfThings, b => {
        b.OwnsOne(v => v.Thing);
    });
    b.OwnsMany(c => c.LastListOfThings);
});

I would've liked to be able to skip all this ceremony and simply specify the OwnsOne and ToJson, but that resulted in errors (because EFCore wants every type in the object graph to be an entity). This is all ok, though, I can deal with this, but when updating the object graph referenced in the OwnedNavigationProperty, I get errors:

System.InvalidOperationException: The property 'OtherListOfThingsType.ThingId' is part of a key and so cannot be modified or marked as modified.

This is confusing to me, starting with the fact that OtherListOfThingsType.ThingId is a property that doesn't actually exist anywhere. Regardless, my real question is:

Is there a way to just tell EFCore, "any time anything is updated in this object graph (and you can leave the detection of that state to me), just re-serialize the whole thing, don't try to reconcile the changes"? Essentially, I want OwningEntityType.OwnedNavigationProperty to be treated like a scalar value, not an object graph of entity types.

This is essentially what Npgsql's old POCO mapping functionality provided, but it is now deprecated.

It looks like what I'm seeking is referred to as complex types with JSON mapping and it is not (yet) implemented. Is there an alternative solution?


Solution

  • Complex types (as opposed to entity types) are exactly the functionality being sought here. The feature to store complex types as JSON instead of in a separate table is not yet implemented, as of this writing.

    Instead, using Postgresql and Npgsql, the "JsonDocument DOM Mapping" is an option, until the built-in EFCore functionality is available.