许多人通过联络表自行加入

时间:2014-08-20 19:41:45

标签: c# entity-framework

我有一个EF模型,可以通过中间类自我引用来定义父/子关系。我知道如何使用Map命令执行纯粹的多对多关系,但由于某种原因,通过此中间类导致我的映射出现问题。中间类为关系提供了附加属性。请参阅下面的类,modelBinder逻辑和错误:

public class Equipment
{        
    [Key]
    public int EquipmentId { get; set; }

    public virtual List<ChildRecord> Parents { get; set; }
    public virtual List<ChildRecord> Children { get; set; }
}

public class ChildRecord
{
    [Key]
    public int ChildId { get; set; }

    [Required]
    public int Quantity { get; set; }

    [Required]
    public Equipment Parent { get; set; }

    [Required]
    public Equipment Child { get; set; }
}

我已尝试在两个方向上构建映射,但我一次只保留一组映射:

        modelBuilder.Entity<ChildRecord>()
            .HasRequired(x => x.Parent)
            .WithMany(x => x.Children )
            .WillCascadeOnDelete(false);

        modelBuilder.Entity<ChildRecord>()
            .HasRequired(x => x.Child)
            .WithMany(x => x.Parents)
            .WillCascadeOnDelete(false);

OR

        modelBuilder.Entity<Equipment>()
            .HasMany(x => x.Parents)
            .WithRequired(x => x.Child)
            .WillCascadeOnDelete(false);

        modelBuilder.Entity<Equipment>()
            .HasMany(x => x.Children)
            .WithRequired(x => x.Parent)
            .WillCascadeOnDelete(false);

无论我使用哪个集合,当我尝试将我的ef模型部署到数据库时,我都会收到错误:The foreign key component 'Child' is not a declared property on type 'ChildRecord'. Verify that it has not been explicitly excluded from the model and that it is a valid primitive property.

如果我在没有使用modelBinder逻辑的情况下构建它,那么我在ChildRecord表中为Child获取两个ID列,为Parent提供两个ID列。这是有道理的,因为它试图从Equipment自动创建导航属性,并且不知道ChildRecord中已经存在满足此需求的属性。

我尝试在类上使用Data Annotations,而没有使用modelBuilder代码,但是失败的错误与上面相同:

    [Required]
    [ForeignKey("EquipmentId")]
    public Equipment Parent { get; set; }

    [Required]
    [ForeignKey("EquipmentId")]
    public Equipment Child { get; set; }

    [InverseProperty("Child")]
    public virtual List<ChildRecord> Parents { get; set; }
    [InverseProperty("Parent")]
    public virtual List<ChildRecord> Children { get; set; }

我已经在互联网/ SO上看了各种其他答案,而且常见的差异似乎是我自我加入,因为我能找到的所有答案都是针对两种不同的类型。

1 个答案:

答案 0 :(得分:0)

如果您定义此类:

public class Equipment
{
    [Key]
    public int EquipmentId { get; set; }

    public virtual List<EquipmentRelation> Parents { get; set; }
    public virtual List<EquipmentRelation> Children { get; set; }
}

public class EquipmentRelation
{
    [Key]
    [Column("ChildId", Order=1)]
    public int ChildId { get; set; }

    [Key]
    [Column("ParentId", Order=2)]
    public int ParentId { get; set; }

    [Required]
    public int Quantity { get; set; }

    [Required]
    public Equipment Parent { get; set; }

    [Required]
    public Equipment Child { get; set; }
}

Code First将正确推断设备件与其父母和子女之间的关系。父母和子女都是可选的。 EquipmentRelation需要父母和孩子。

与原始代码的不同之处在于关联表包含一个复合键,其中包含父设备和子设备的PK。 (我已将其重命名为EquipmentRelation)。

如果您想对其进行微调或“编码文档”,您当然可以使用Fluent API来表达推断的关系。

注意:Column属性是必需的,因为当您使用属性定义复合键时,EF需要知道键中列的顺序。或者,您可以使用Fluent API HasKey

定义此密钥