EF Code First - Reuse table for nested OwnsMany mapping

Viewed 316

I am trying to use Owned entity types for a model with nested OwnsOne->OwnsMany relationship of the same types, as described in code below. I can create separate tables ('Parent_Foo_Identifiers' + 'Parent_Bar_Identifiers') for the Identifiers which works, but is there a way to model this so that the same table (e.g. 'Parent_Child_Identifiers') is used for all Identifiers?

For 2 properties using multiple tables seems acceptable, but if I add another Child Baz then I would need another table, etc...

I have tried adding a property with default value 'Foo'|'Bar' to Identifiers and using that within the PK as a discriminator, but EFCore didn't recognise my attempted config.

Implementation with separate tables:

Model: Parent always has one Foo. Parent may have one Bar. Foo/Bar + associated Identifiers do not exist without a Parent. Identifiers are unique by Parent.[Foo|Bar] + Key, e.g. for a given Parent.Id, Foo and Bar may both have an Identifier with Key 'abc', but only one 'abc' entry each.

public class Parent
{
    public Guid Id { get; set; }
    public Child Foo { get; set; }
    public Child? Bar { get; set; }
}

public class Child
{
    public List<Identifier> Identifiers { get; set; }
}

public class Identifier
{
    public string Key { get; set; }
    public string Value { get; set; }
}

DbContext:

public class MyContext: DbContext
{
    internal DbSet<Parent> Parents { get; set; }

    public MyContext(DbContextOptions<MyContext> options): base(options) { }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Parent>().HasKey(p => p.Id);

        modelBuilder.Entity<Parent>().OwnsOne(p => p.Foo, foo =>
        {
            foo.OwnsMany<Identifier>(f => f.Identifiers, m =>
            {
                m.WithOwner().HasForeignKey("Id");
                m.HasKey("Id", "Key");
                m.ToTable("Parent_Foo_Identifiers");
            });
        });

        modelBuilder.Entity<Parent>().OwnsOne(p => p.Bar, bar =>
        {
            bar.OwnsMany<Identifier>(f => f.Identifiers, m =>
            {
                m.WithOwner().HasForeignKey("Id");
                m.HasKey("Id", "Key");
                m.ToTable("Parent_Bar_Identifiers");
            });
        });
    }
}
1 Answers

The solution that immediately comes to mind is this :

  • List<Identifier> Identifiers { get; set; } is moved to the parent
  • class Child is dropped entirely
  • Class Identifier has an extra column named ChildId to be able to group the identifiers by child (hence being able to get the identifiers that belong to Foo and/or or the ones that belong to Bar -- if any)
Related