![](/img/trans.png)
[英]How to refactor out base entity configurations to a separate class in Entity Framework Core Fluent API
[英]Entity framework Fluent API does not consider base class properties
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,因此也應該有效),對嗎?
其次,在刪除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<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);
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.