EF 6.1:
我们刚刚开始了一个有很多pf继承的项目。选定的继承db映射类型是每个层次结构的表。问题是,在尝试使用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<SER> 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<SER> ListOfSER { get; set; }
}
public class SDContext : BaseContext
{
public DbSet<Version> Versions { get; set; }
public DbSet<AbstractD> Ds { get; set; }
public DbSet<AbstractR> 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<T> : EntityTypeConfiguration<T> 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<Version>
{
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<AbstractR>
{
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<SER>
{
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<AbstractD>
{
public AbstractDConfiguration() : base()
{
this.ToTable("Defs");
}
}
public class SEDConfiguration : BaseObjectConfiguration<SED>
{
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配置中定义(因为SER继承自AbstractR也应该有效),我是对的吗?
其次,删除版本属性&amp;映射时,SER映射中使用的“ChildId”和“ParentId”属性出现相同的问题。这是一个已知的问题吗?我做错了吗?
PS:为简单起见,已移除ParentId映射,因为它似乎与ChildId映射存在相同的问题。
有谁知道为什么会出现这种问题?
更新
经过一些研究后,似乎Fluent API无法使用基类属性进行映射。是对的吗 ?这是一种通缉行为吗?为什么DataAnnotations能够使用基类属性而不能使用Fluent API?是不是所有基类属性都插入到每个类中,或者是否使用某种装饰模式读取它?
答案 0 :(得分:3)
只要主体也使用类型基类的导航属性,您就可以使用基类属性作为外键关联。
Principal(Version
)声明ListOfSER
为SER
类型的导航属性为Dependent
public class Version : BaseObject
{
public virtual ICollection<SER> ListOfSER { get; set; }
}
,但配置使用基类属性(VersionId
)作为外键关联
public class VersionConfiguration : BaseObjectConfiguration<Version>
{
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);
}
解决方案1 会将ListOfSER
类型从SER
更改为AbstractR
。
public class Version : BaseObject
{
public virtual ICollection<AbstractR> ListOfSER { get; set; }
}
这将更有意义,VersionId
是在基类上定义的,任何派生类型都应该能够使用这个外键关联,对吧?但遗憾的是,Version
类型只允许SER
与Version
相关联。
定义流畅的api配置时也存在不一致。
public class VersionConfiguration : BaseObjectConfiguration<Version>
{
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<AbstractR>
{
public AbstractRConfiguration()
: base()
{
HasRequired(ar => ar.Version)
.WithMany() // -> this should be WithMany(x => x.ListOfSER)
.HasForeignKey(ar => ar.VersionId)
.WillCascadeOnDelete(false);
}
}
更重要的是,您不必同时配置。只需将其放在VersionConfiguration
或AbstractRConfiguration
即可。
解决方案2 会将Version
和VersionId
从基类移至SER
,如果您只希望Version
关联与SER
。
public class Version : BaseObject
{
public virtual ICollection<SER> 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<Version>
{
public VersionConfiguration()
: base()
{
HasMany(mdv => mdv.ListOfSER)
.WithRequired(x => x.Version)
.HasForeignKey(ser => ser.VersionId)
.WillCascadeOnDelete(false);
}
}
public class SERConfiguration : BaseObjectConfiguration<SER>
{
public SERConfiguration()
: base()
{
HasRequired(ar => ar.Version)
.WithMany(x => x.ListOfSER)
.HasForeignKey(ar => ar.VersionId)
.WillCascadeOnDelete(false);
}
}