循环关系的实体框架外键

时间:2018-03-30 14:53:48

标签: c# entity-framework ef-code-first migration entity-framework-core

我正在将应用程序转换为Entity Framework Core,并且在我的两个模型类之间获取外键关系时遇到了麻烦。类是这样设置的(注意在--- title: "test" author: "Stéphane Laurent" date: "30 mars 2018" output: pdf_document: includes: in_header: header.tex --- 上声明了Guid Id字段):

BaseEntity

关系背后的想法是,一个public class Crt : BaseEntity { [Required] public Guid FacId { get; set; } [Required] public string Code { get; set; } [ForeignKey("ActiveCrtChk") public Guid? ActiveCrtChkId { get; set; } public string Description { get; set; } public string Device { get; set; } #region navigation properties public CrtChk ActiveCrtChk; public List<CrtChk> CartChecks; #endregion } public class CrtChk : BaseEntity { [Required] public Guid CrtId { get; set; } [Required] public string Device { get; set; } [Required] public Guid OutSysUsrId { get; set; } [Required] public DateTime OutSysDateTime { get; set; } public Guid? InSysUsrId { get; set; } public DateTime? InSysDateTime { get; set; } [Required] public string Type { get; set; } #region navigation properties public Crt Cart { get; set; } public Usr OutSysUsr { get; set; } public Usr InSysUsr { get; set; } public List<CrtEvt> CartEvents { get; set; } #endregion } 可以包含多个Crt条记录,但CrtChk也会存储活动Crt Id记录。

当我运行迁移时,它会生成CrtChkCrt之间所期望的所有外键关系,除了没有为CrtChk字段生成外键。

通过阅读this post我的理解是ActiveCrtChkId属性ForeignKey属性的ActiveCrtChkId导航属性的名称,我应该得到一个外国人我的迁移中的关键约束。

我在这里缺少什么?

修改

在修正了将ActiveCrtChk导航属性声明为字段的错误后,我在尝试创建迁移时偶然发现了一个新错误。

Crt

我认为Unable to determine the relationship represented by navigation property 'Crt.ActiveCrtChk' of type 'CrtChk'. Either manually configure the relationship, or ignore this property using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'. 属性是手动配置关系的吗?我是否需要使用Fluent API来创建关系?如果是这样,我如何使用Fluent API建立一对一(ForeignKeyCrt)和一对多(与ActiveCrtChk关联的所有CrtChks的关系)?

1 个答案:

答案 0 :(得分:2)

这是可能的,但由于这种设计会在两个实体之间产生循环依赖,因此会导致很多问题。例如,不仅一个关系(假设从return "production code that should operate with different variations of $amounte and $redeem on last iteration"; CrtChk)不能使用级联删除,而且您不能在不首先更新{{1}的情况下删除Crt } Crt(并调用ActiveCrtChkId)。

无论如何,这是您配置所需关系的方式。通常使用null属性来解决导航属性映射歧义就足够了,但是一对一的单向(即仅在一端具有导航属性)需要流畅的配置(否则它将按惯例映射)一对多)。还特别针对关系,我发现明确的流畅配置比考虑所有EF常规假设和数据注释更明确,比如放置SaveChanges属性(在FK属性或导航属性上),放在那里的第一个或更晚的字符串案例等。

不久,以下是相关关系的完整显式配置:

InverseProperty

请注意,ForeignKey属性不能在两种关系中使用。首先,因为每个导航属性只能映射到一个关系。其次,因为关系模型不能强制// Crt 1 - 0..N CrtChk modelBuilder.Entity<Crt>() .HasMany(e => e.CartChecks) .WithOne(e => e.Cart) .HasForeignKey(e => e.CrtId) .OnDelete(DeleteBehavior.Cascade); // CrtChk 1 - 0..1 Crt modelBuilder.Entity<Crt>() .HasOne(e => e.ActiveCrtChk) .WithOne() .HasForeignKey<Crt>(e => e.ActiveCrtChkId) .OnDelete(DeleteBehavior.Restrict); FK引用的Cart记录与引用它的CrtChk的{​​{1}}具有相同的ActiveCrtChkId - 它可以任何其他(虽然逻辑上意图不同)。