同一实体类型的一对一和一对多

时间:2018-05-29 21:42:12

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

我正在尝试设计以下实体关系

  • 计划
  • 装配

程序可以有多个程序集。其中一个组件将是一个主组件。每个程序集只属于一个程序。

这些类的建模如下:

public class Program
{
    public int Id {get;set;}
    public virtual ProgramAssembly MainAssembly {get;set;}
    public virtual ICollection<ProgramAssembly> Assemblies {get;set;}
}

public class ProgramAssembly
{
   public int Id {get;set;}
   public virtual Program Program {get;set;}
   public int ProgramId {get;set;}
}

我没有用FluentApi指定任何东西(但是,我没有反对它) 使用上面的代码,我收到此错误:

  

保存不公开其关系的外键属性的实体时发生错误。 EntityEntries属性将返回null,因为无法将单个实体标识为异常源。通过在实体类型中公开外键属性,可以更轻松地在保存时处理异常。有关详细信息,请参阅InnerException。

     

InnerException:无法确定相关操作的有效排序。由于外键约束,模型要求或存储生成的值,可能存在依赖关系。

我尝试将ProgramAssembly更改为以下

public class ProgramAssembly
{
    [ForeignKkey("Program")]
    public int Id {get;set;}
    public virtual Program Program {get;set;}
}

然而,我得到了这个错误:

  

ProgramAssembly_Program_Source ::多重性在关系'ProgramAssembly_Program'中的角色'ProgramAssembly_Program_Source'中无效。由于“从属角色”是指关键属性,因此从属角色的多重性的上限必须为“1”。

我还尝试了以下流畅的API方法

modelBuilder.Entity<ProgramAssembly>()
   .HasRequired(a => a.Program)
   .WithMany(p => p.Assemblies);

public class ProgramAssembly
    {        
        public int Id { get; set; }
        public virtual Program Program { get; set; }
        [ForeignKey("Program")] //same error with or without this attribute
        public int ProgramId { get; set; }
   }

然后错误是:

  

保存不公开其关系的外键属性的实体时发生错误。 EntityEntries属性将返回null,因为无法将单个实体标识为异常源。通过在实体类型中公开外键属性,可以更轻松地在保存时处理异常。有关详细信息,请参阅InnerException。   UpdateException:无法确定依赖操作的有效排序。由于外键约束,模型要求或存储生成的值,可能存在依赖关系。

如何在不改变在Assembly上添加'IsPrimary'属性的方法的情况下允许该关系?

我在SO上看到了一些类似的问题,但它们或者是关于EF核心的,比如this one,或者提出了重要的逻辑更改,例如this one,甚至是this one,甚至没有编译

2 个答案:

答案 0 :(得分:1)

您需要通知EF您的主键和外键如何工作。您需要添加属性来定义主键[Key]并定义外键并向导航属性添加属性以定义作为外键的字段。

public class Program
{
    [Key]
    public int Id {get;set;}
    public int MainAssemblyId {get;set;}
    [ForeignKey("MainAssemblyId ")]
    public virtual ProgramAssembly MainAssembly {get;set;}
    public virtual ICollection<ProgramAssembly> Assemblies {get;set;}
}

public class ProgramAssembly
{
   [Key]
   public int Id {get;set;}
   [ForeignKey("ProgramId")]
   public virtual Program Program {get;set;}
   public int ProgramId {get;set;}
}

答案 1 :(得分:0)

以下代码将满足您的要求。

public class Program
{
    [Key]
    public int Id {get;set;}
    public virtual ICollection<ProgramAssembly> Assemblies {get;set;}
}

public class ProgramAssembly
{
   public int Id {get;set;}

   [ForeignKey("ProgramId")]
   public virtual Program Program {get;set;}
   public int ProgramId {get;set;}
   public bool IsMainProgramAssembly
}

如果需要,您可以[Required]使用ProgramId,或者也可以将ProgramId视为可空。