1

EDIT: This question here makes it clear that this is an architectural problem with Entity Framework, and it is not supported to have foreign keys to these sorts of inherited properties.

When Entity Framework pulls a property (CompanyId) out of an abstract base class to use as a foreign key, how do I use that property in additional foreign keys without getting the error below or adding additional properties which duplicate the data?

I've included the output the previous developer got, and what I want to get, and why they are different at the end. The question is whether it is possible to get the generated migration to reuse the CompanyId field.

Error message:

The foreign key component 'CompanyId' is not a declared property on type 'XXXNote'. Verify that it has not been explicitly excluded from the model and that it is a valid primitive property.

Mapping class:

class XXXNoteMap : CompanyObjectMap<XXXNote>
{
    public XXXNoteMap()
    {
        Map(m => m.ToTable("db_XXXNote"));
        HasKey(k => new { k.CompanyId, k.Id });
        HasRequired(c => c.XXX).WithMany().HasForeignKey(k => new { k.CompanyId, k.XXXId });
    }
}

CompanyObjectMap class:

public class CompanyObjectMap<T> : EntityTypeConfiguration<T>
    where T:CompanyObject
{
    public CompanyObjectMap()
    {
        this.HasRequired(c => c.Company).WithMany().HasForeignKey(c => c.CompanyId);
    }
}

XXXNote class:

public class XXXNote : Note
{
    public Guid XXXId { get; set; }

    public virtual XXX XXX { get; set; }
}

Note class:

public abstract class Note : CompanyObject
{
    public Guid Id { get; set; }

    public string Description { get; set; }
}

CompanyObject class:

// The ICompanyObject interface can be removed and the problem remains.
public abstract class CompanyObject : DataObject, ICompanyObject
{
    // Removing the virtual keyword has no effect.
    public virtual Guid CompanyId { get; set; }

    public virtual Company Company { get; set; }
}

ICompanyObject class:

// This interface can be removed and the problem remains.
public interface ICompanyObject
{
    Guid CompanyId { get; set; }
}

Additional context:

The previous developer worked around this by adding a new property to the XXXNote class, XXXCompanyId. They then used that in the manually created foreign key, instead of the automatically included CompanyId I am trying to use above.

Old incorrect generated code from the previous developers broken approach:

        CreateTable(
            "dbo.db_XXXNote",
            c => new
                {
                    CompanyId = c.Guid(nullable: false),
                    Id = c.Guid(nullable: false),
                    XXXId = c.Guid(nullable: false),
                    XXXCompanyId = c.Guid(nullable: false),
                })
            .PrimaryKey(t => new { t.CompanyId, t.Id })
            .ForeignKey("dbo.db_Note", t => new { t.CompanyId, t.Id })
            .ForeignKey("dbo.db_XXX", t => new { t.XXXCompanyId, t.XXXId })
            .Index(t => new { t.CompanyId, t.Id })
            .Index(t => new { t.XXXCompanyId, t.XXXId });

The desired output:

        CreateTable(
            "dbo.db_XXXNote",
            c => new
                {
                    CompanyId = c.Guid(nullable: false),
                    Id = c.Guid(nullable: false),
                    XXXId = c.Guid(nullable: false),
                })
            .PrimaryKey(t => new { t.CompanyId, t.Id })
            .ForeignKey("dbo.db_Note", t => new { t.CompanyId, t.Id })
            .ForeignKey("dbo.db_XXX", t => new { t.CompanyId, t.XXXId })
            .Index(t => new { t.CompanyId, t.Id })
            .Index(t => new { t.CompanyId, t.XXXId });
Community
  • 1
  • 1
  • Remove `virtual` from `CompanyId` in your `CompanyObject` class? – TestWell Sep 28 '15 at 21:48
  • No, that's a random guess, and does not work. – yourpublicdisplayname Sep 28 '15 at 22:07
  • my guess is EF may not recognize the interface `ICompanyObject`, it assumes the property `CompanyId` does not exist in the class. Try not using interface (for testing) to see if that is the issue. – Hopeless Sep 29 '15 at 01:04
  • similar problem here http://stackoverflow.com/questions/9805329/how-to-use-interface-properties-with-codefirst – Hopeless Sep 29 '15 at 01:24
  • That problem has someone actually using EF attributes on properties in the interface. In my case, the interface merely defines the presence of a property - which is also defined on the accompanying CompanyObject class. I can of course verify it by not using the interface as you suggest, but that would have to be in a comparable contrived test case as there is so much other code expecting the presence of the interface in the code base. If I can find the time tomorrow I'll give it a shot. I suspect though, it's more likely that EF cannot find it because of the primary key usage. – yourpublicdisplayname Sep 29 '15 at 02:45
  • some ones there said clearly that EF does not support entity with interface, not mentioning about the DataAnnotation if it is involved. Also the accepted answer even suggests using NHibernate instead of EF. – Hopeless Sep 29 '15 at 02:52
  • Too many assumptions. – yourpublicdisplayname Sep 29 '15 at 18:28
  • Note that I have completely removed the interface, and the problem remains. – yourpublicdisplayname Sep 30 '15 at 01:38
  • I don't think it's a matter of Interfaces, I have experienced a similar problem and the problem is solved when I move the child relation to the parent object. it's more like a mapping problem. like this foreign key has been mapped to the parent object and cannot be used for the child. – Hossein Shahdoost Feb 05 '16 at 05:39
  • There's an edit at the top of the question showing that the related functionality is limited, and the limitation is too complicated to fix/not worth fixing if I recall correctly. – yourpublicdisplayname Feb 06 '16 at 07:02

1 Answers1

0

This question here makes it clear that this is an architectural problem with Entity Framework, and it is not supported to have foreign keys to these sorts of inherited properties.

I originally had this at the top of the question, but someone still commented so I've marked the question as answered to stop wasting people's time.

Community
  • 1
  • 1