代码之家  ›  专栏  ›  技术社区  ›  James Hogle

循环关系的实体框架外键

  •  2
  • James Hogle  · 技术社区  · 7 年前

    我正在将应用程序转换为实体框架核心,在获取两个模型类之间的外键关系时遇到了麻烦。类的设置如下(请注意,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 记录,但 阴极射线管 还存储 Id号 忙碌的 CrtChk公司 记录

    当我运行迁移时,它会生成我所期望的所有外键关系 阴极射线管 CrtChk公司 除非没有为生成外键 ActiveCrtChkId 领域

    这是我从阅读中得到的理解 this post 拥有 ForeignKey 上的属性 ActiveCrtChkId 属性的名称 ActiveCrtChk 导航属性,我应该在迁移中获得外键约束。

    我错过了什么?

    编辑

    在纠正了我的错误后 阴极射线管 导航属性作为字段,我在尝试创建迁移时遇到了一个新错误。

    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建立一对一的关系( 阴极射线管 ActiveCrtChk )以及一对多(所有与 阴极射线管 )?

    1 回复  |  直到 7 年前
        1
  •  3
  •   Ivan Stoev    7 年前

    这是可能的,但由于这种设计在两个实体之间创建了循环依赖关系,因此会给您带来很多问题。例如,不仅仅是一种关系(比如 CrtChk Crt )不能使用级联删除,但也不能简单地删除 阴极射线管 无需首先更新 ActiveCrtChkId null (和呼叫 SaveChanges )。

    无论如何,下面是如何配置所需关系的。通常使用它就足够了 InverseProperty 属性来解决导航属性映射的模糊性,但一对一单向(即导航属性仅位于一端)需要流畅的配置(否则将按照约定映射为一对多)。特别是对于关系,我发现显式流畅配置比考虑所有EF常规假设和数据注释(如放置位置)要清楚得多 ForeignKey 属性(在FK属性或导航属性上),放置的字符串是第一个或后面的大小写等。

    简而言之,以下是相关关系的完整明确配置:

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

    请注意 Cart 属性不能同时用于这两种关系。首先,因为每个导航属性只能映射到一个关系。其次,因为关系模型不能强制执行 CrtChk公司 记录引用人 ActiveCrtChkId FK具有相同的 CrtId 作为 Id 阴极射线管 引用它-它可以是任何其他的(尽管从逻辑上来说,意图是不同的)。

    推荐文章