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 });