postgresqlentity-framework-coreef-code-firstentity-framework-migrationsef-code-first-mapping

Mapping inheritance structure in Entity Framework Core to Postgres - Conflicting Error Messages


I have a number of inheritance hierarchies in my model. I'm using Entity Framework Core 3.1.2 with a Postgres database. Code First. I am trying to create a migration to generate my database tables.

I mapped my first abstract object

public DbSet<Asset> Assets { get; set; }

I learn that you can't map an abstract class without mapping a concrete descendant.

The corresponding CLR type for entity type 'Asset' is not instantiable and there is no derived entity type in the model that corresponds to a concrete CLR type.

So I map the descendants.

public DbSet<LinearAsset> LinearAssets { get; set; }
public DbSet<StructureAsset> Structures { get; set; }
public DbSet<BridgeAsset> Bridges { get; set; }
public DbSet<RoadAsset> Roads { get; set; }

and everything is good. Fantastic.

However. When I come to map my second inheritance hierarchy (and any other that I try) I get into this weird circular argument where I both must and must not map the children.

public DbSet<Attachment> Attachments { get; set; }
public DbSet<AssetAttachment> AssetAttachments { get; set; }

gives me

The entity type 'AssetAttachment' cannot be mapped to a table because it is derived from 'Attachment'. Only base entity types can be mapped to a table.

If I remove the mapping for AssetAttachments, I'm back to this

The corresponding CLR type for entity type 'Attachment' is not instantiable and there is no derived entity type in the model that corresponds to a concrete CLR type.

I've not been able to find any meaningful difference between the Asset inheritance hierarchy, which worked, and the other inheritance hierarchies, that don't work.

I've tried various different ways of mapping, or not mapping the descendant objects, but it always comes back to getting one of the two above error messages. I am both expected to map and not map the descendants, leaving me very confused as to what Dot Net actually wants from me.

Is anybody able to give me some advice on how I am to deal with these two conflicting error messages?


Solution

  • It turns out, the problem was that I was converting the table names to snake case, to be consistence with postgres convention. Making the field names snake case was fine, but making the table names snake case introduced the error I describe above.

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            foreach (var entity in modelBuilder.Model.GetEntityTypes())
            {
                // THIS IS WHAT CAUSES THE ISSUE
                if (!String.IsNullOrWhiteSpace(entity.GetTableName()) && (entity.GetTableName() != entity.GetTableName().ToLower()))
                    entity.SetTableName(ToSnakeCase(entity.GetTableName()));
    
                // THIS IS OKAY
                foreach (var property in entity.GetProperties())
                {
                    property.SetColumnName(ToSnakeCase(property.GetColumnName()));
                }
            }
            base.OnModelCreating(modelBuilder);
        }