2

I am having troubles implementing a table-per-hierarchy architecture in combination with a one-to-one relation in EF 6 code-first and SQL-Server. Entity Framework doesn't use the right column as foreign key.

I have a class Version and two inheriting classes ProductVersion and FeatureVersion.

public class Version
{
    [Key]
    public Int32 ID { get; private set; }
    public Int32 Major { get; private set; }
    public Int32 Minor { get; private set; }
    public Int32 Patch { get; private set; }
    ..
}

The two inheriting classes implement nothing but the navigation properties.

public class ProductVersion : Version
{
    [Required]
    public virtual Product.Product Product { get; set; }
    public Int32 ProductId { get; set; }
}

public class FeatureVersion : Version
{
    [Required]
    public virtual Feature Feature { get; set; }
    public Int32 FeatureId { get; set; }
}

Now in my product I use a one-to-many relation and everything works fine.

public class Product
{
    public Int32 ID { get; set; }
    public String Name { get; set; }

    public List<Versioning.ProductVersion> ProductVersions { get; set; }
    ...
}

In my feature I use a one-to-one relation and things get wrong.

public class Feature : ICloneable
{
    public Int32 Id { get; set; }

    ...

    public int FeatureVersionId { get; set; }
    public virtual Entities.Versioning.FeatureVersion FeatureVersion { get; set; }
    ...
}

The resulting migration looks like this

CreateTable(
            "dbo.Versions",
            c => new
                {
                    ID = c.Int(nullable: false),
                    ...,
                    FeatureId = c.Int(),
                    ProductId = c.Int(),
                    Discriminator = c.String(nullable: false, maxLength: 128),
                })
            .PrimaryKey(t => t.ID)
            .ForeignKey("dbo.Features", t => t.ID)
            .ForeignKey("dbo.Products", t => t.ProductId, cascadeDelete: true)
            .Index(t => t.ID)
            .Index(t => t.ProductId);

As you see the foreign key to Features is using the wrong column.

When I change t => t.ID manually to t => t.FeatureId, cascadeDelete: true the foreign key gets inserted correctly into the database, but EF seems to have a problem inserting new features with an initial FeatureVersion; the new FeatureVersion's FeatureId column is always set to 0 and therefore leading to an exception (in the code I simply assign a new FeatureVersion object to the Feature object and try to save the context changes). Everything works fine for Product with its one-to-many relation.

Interestingly when I change the reference in Feature from

public List<Versioning.ProductVersion> ProductVersions { get; set; }

to

public List<Versioning.Version> Versions { get; set; }

e.g. the mother class, everything works fine; in the migration I see the right columns joined and the INSERT works as well. But definitely, this is not what I want.

Is the inheritance somehow irritating EF? Am I missing an important point?

I also tried to change to relation for FeatureVersion to a one-to-many relation same as for Product. It works fine but this isn't the relation I need to use.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Martin Stimpfl
  • 111
  • 1
  • 8
  • 1
    Take a look at [Shared Primary Key Associations](http://weblogs.asp.net/manavi/associations-in-ef-4-1-code-first-part-3-shared-primary-key-associations), I think the way EF handles `one-to-one` relationships cannot be combined with TPH. – Ivan Stoev Jun 13 '16 at 07:11
  • Great question, I've spent a day trying to figure it out, but leaning towards a different solution (like TPC) now. – marijnz0r Sep 10 '18 at 09:46

0 Answers0