我有一个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上看了各种其他答案,而且常见的差异似乎是我自我加入,因为我能找到的所有答案都是针对两种不同的类型。
答案 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