entity frameworkFluent API不考虑基类属性

EF 6.1:

我们刚刚开始了一个有很多pfinheritance的项目。 选定的inheritancedb映射类型是每个层次结构的表。 问题是,在尝试使用add-migration生成迁移时,会引发以下错误:

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

以下是使用的类和配置类:

 public class Version : BaseObject { public virtual ICollection ListOfSER { get; set; } } public abstract class AbsractR : BaseObject { public int ParentId { get; set; } public int ChildId { get; set; } public int VersionId { get; set; } public virtual Version Version { get; set; } } public class SER : AbstractR { public int SEDId { get { return base.ChildId; } set { base.ChildId = value; } } public virtual SED SED { get; set; } } public abstract class AbstractD : BaseObject { } public class SED : AbstractD { public virtual ICollection ListOfSER { get; set; } } public class SDContext : BaseContext { public DbSet Versions { get; set; } public DbSet Ds { get; set; } public DbSet Rs { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); modelBuilder.Configurations.Add(new VersionConfiguration()); #region Refs modelBuilder.Configurations.Add(new AbstractRConfiguration()); modelBuilder.Configurations.Add(new SERConfiguration()); #endregion #region Defs modelBuilder.Configurations.Add(new AbstractDConfiguration()); modelBuilder.Configurations.Add(new SEDConfiguration()); #endregion } } public class BaseObjectConfiguration : EntityTypeConfiguration where T : BaseObject { public BaseObjectConfiguration() { #region Key this.HasKey(bo => bo.Id); #endregion #region Properties this.Property(bo => bo.Id).IsRequired(); this.Property(bo => bo.IsDeleted).IsRequired(); this.Property(bo => bo.LastModificationDate).IsOptional(); this.Property(bo => bo.OptimisticVersion).IsConcurrencyToken().IsRequired().IsRowVersion(); this.Property(bo => bo.CreationDate).IsRequired(); this.Property(bo => bo.DeletionDate).IsOptional(); #endregion } } public class VersionConfiguration : BaseObjectConfiguration { public VersionConfiguration() : base() { #region Properties #endregion #region Objects this.HasMany(mdv => mdv.ListOfSER).WithRequired().HasForeignKey(ser => ser.VersionId).WillCascadeOnDelete(false); #endregion #region Table this.ToTable("Versions"); #endregion } } public class AbstractRConfiguration : BaseObjectConfiguration { public AbstractRConfiguration() : base() { #region Properties this.Property(ser => ser.VersionId).IsRequired(); #endregion #region Objects this.HasRequired(ar => ar.Version).WithMany().HasForeignKey(ar => ar.VersionId).WillCascadeOnDelete(false); #endregion #region Table this.ToTable("Refs"); #endregion } } public class SERConfiguration : BaseObjectConfiguration { public SERConfiguration() : base() { #region Properties this.Ignore(ser => ser.SEDId); #endregion #region Objects this.HasRequired(ser => ser.SED).WithMany(sed => sed.ListOfSER).HasForeignKey(ser => ser.ChildId).WillCascadeOnDelete(false); #endregion #region Table this.ToTable("Refs"); #endregion } } public class AbstractDConfiguration : BaseObjectConfiguration { public AbstractDConfiguration() : base() { this.ToTable("Defs"); } } public class SEDConfiguration : BaseObjectConfiguration { public SEDConfiguration() : base() { #region Properties #endregion #region Objects this.HasMany(sed => sed.ListOfSER).WithRequired(sed => sed.SED).HasForeignKey(sed => sed.ChildId).WillCascadeOnDelete(false); #endregion #region Table this.ToTable("Defs"); #endregion } } 

我知道我们可以使用[ForeignKey]属性来告诉派生类的导航属性应该使用父抽象类中定义的列。 我们希望避免使用DataAnnotations。 我只是不明白为什么它会抛出这个错误。 “Version”导航属性在AbstractR配置中定义,而不是在SER配置中定义(由于SERinheritance自AbstractR,因此也应该有效),对吗?

其次,在删除Version属性和映射时,SER映射中使用的“ChildId”和“ParentId”属性会出现同样的问题。 这是一个已知的问题吗? 难道我做错了什么 ?

PS:为简单起见,已删除ParentId映射,因为它似乎与ChildId映射的问题相同。

有谁知道为什么会出现这种问题?


UPDATE

经过一些研究后,似乎Fluent API无法使用基类属性进行映射。 是对的吗 ? 这是想要的行为吗? 为什么DataAnnotations能够使用基类属性而不能使用Fluent API? 是不是所有的基类属性都插入到每个类中,或者是否使用某种装饰模式进行读取?

只要主体还使用类型基类的导航属性,您就可以使用基类属性作为外键关联。

Principal( Version )已将ListOfSER声明为SER类型的导航属性为Dependent

 public class Version : BaseObject { public virtual ICollection ListOfSER { get; set; } } 

,但配置使用基类属性( VersionId )作为外键关联

 public class VersionConfiguration : BaseObjectConfiguration { public VersionConfiguration() : base() { HasMany(mdv => mdv.ListOfSER) .WithRequired() .HasForeignKey(ser => ser.VersionId) // -> belongs to base class .WillCascadeOnDelete(false); } } 

在配置ForeignKeyConstraintConfiguration时不允许这样做,请查看代码摘录

 foreach (var dependentProperty in dependentPropertyInfos) { var property = dependentEnd.GetEntityType() // -> SER .GetDeclaredPrimitiveProperty(dependentProperty); // -> VersionId if (property == null) // VersionId is not part of SER metamodel { throw Error.ForeignKeyPropertyNotFound( dependentProperty.Name, dependentEnd.GetEntityType().Name); } dependentProperties.Add(property); } 

解决方案1ListOfSER类型从SER更改为AbstractR

 public class Version : BaseObject { public virtual ICollection ListOfSER { get; set; } } 

这样会更有意义, VersionId是在基类上定义的,任何派生类型都应该能够使用这个外键关联,对吧? 但不幸的是, Version类型只允许SERVersion相关联。

定义流畅的api配置时也会出现不一致。

 public class VersionConfiguration : BaseObjectConfiguration { public VersionConfiguration() : base() { HasMany(mdv => mdv.ListOfSER) .WithRequired() // -> this should be WithRequired(x => x.Version) .HasForeignKey(ser => ser.VersionId) .WillCascadeOnDelete(false); } } public class AbstractRConfiguration : BaseObjectConfiguration { public AbstractRConfiguration() : base() { HasRequired(ar => ar.Version) .WithMany() // -> this should be WithMany(x => x.ListOfSER) .HasForeignKey(ar => ar.VersionId) .WillCascadeOnDelete(false); } } 

更重要的是,您不必同时配置。 只需将它放在VersionConfigurationAbstractRConfiguration

解决方案2是将VersionVersionId从基类移动到SER ,如果您希望Version仅与SER关联。

 public class Version : BaseObject { public virtual ICollection ListOfSER { get; set; } } public abstract class AbstractR : BaseObject { } public class SER : AbstractR { public int VersionId { get; set; } public virtual Version Version { get; set; } } 

并在Version配置或SER配置上进行配置。

 public class VersionConfiguration : BaseObjectConfiguration { public VersionConfiguration() : base() { HasMany(mdv => mdv.ListOfSER) .WithRequired(x => x.Version) .HasForeignKey(ser => ser.VersionId) .WillCascadeOnDelete(false); } } public class SERConfiguration : BaseObjectConfiguration { public SERConfiguration() : base() { HasRequired(ar => ar.Version) .WithMany(x => x.ListOfSER) .HasForeignKey(ar => ar.VersionId) .WillCascadeOnDelete(false); } }