我目前正在尝试实现一个自定义的代码优先链接表,它引用同一个实体两次 - 实质上允许Person
实体拥有一个关联的Person
实体列表。这些类看起来像这样:
[Table("person")]
public class Person : BaseEntity, IEntityInterface
{
[StringLength(255)]
public string GivenName { get; set; }
[StringLength(255)]
public string MiddleNames { get; set; }
[StringLength(255)]
public string FamilyName { get; set; }
public List<PersonPerson> Persons { get; set; }
<other columns>
}
[Table("personperson")]
public class PersonPerson : BaseEntitiesObject
{
[StringLength(50)]
public string Type { get; set; }
[ForeignKey("Person_ID")]
public virtual Person Person { get; set; }
[ForeignKey("OtherPerson_ID")]
public virtual Person OtherPerson { get; set; }
[Column("Person_ID")]
public Guid Person_ID { get; set; }
[Column("OtherPerson_ID")]
public Guid OtherPerson_ID { get; set; }
<more columns>
}
这适用于创建链接 - 左侧ID最终位于Person_ID
,右侧位于OtherPerson_ID
,并且链接很愉快。但是,只要从数据库中查询Person
对象,查询就会如下所示:
SELECT
1 AS `C1`,
`Extent1`.`ID`,
`Extent1`.`Type`,
`Extent1`.`Person_ID`,
`Extent1`.`OtherPerson_ID`,
`Extent1`.`Jurisdiction`,
`Extent1`.`EffectiveDate`,
`Extent1`.`ExpiryDate`,
`Extent1`.`Created`,
`Extent1`.`CreatedBy`,
`Extent1`.`Updated`,
`Extent1`.`UpdatedBy`,
`Extent1`.`Source`,
`Extent1`.`Person_ID1`
FROM `personperson` AS `Extent1`
WHERE (`Extent1`.`Person_ID1` IS NOT NULL) AND (`Extent1`.`Person_ID1` = @EntityKeyValue1)
它试图在Person_ID1
中找到左手ID,尽管属性告诉它使用哪个列作为外键关系并明确说明该列的名称应该是什么。这种情况发生的唯一地方是链接表引用同一个实体两次,所以我认为这与它有关,但我不知道该怎么办。
答案 0 :(得分:3)
您在Person
实体中有两个 PersonPerson
引用导航属性(因此两个关系),但单 Person
类中的集合导航属性。
没有额外的数据注释/流畅的配置EF不知道两个关系中的哪一个应该映射集合,因此按照惯例,它默认地假定第三个(!)单向(即仅使用集合) relationship,因此您在SQL查询中看到的附加列。
如果两个实体之间有多个关系,则需要正确配置(映射)它们。通常可以使用InverseProperty
数据注释,但这种关系会引入多级联路径问题,并且由于one-to-many
关系默认情况下有级联删除,因此确实需要使用流畅的配置来映射和关闭级联删除。
以下是您的模型的配置:
// first relationship
modelBuilder.Entity<PersonPerson>()
.HasRequired(e => e.Person)
.WithMany(e => e.Persons)
.HasForeignKey(e => e.Person_ID)
.WillCascadeOnDelete(false);
// second relationship
modelBuilder.Entity<PersonPerson>()
.HasRequired(e => e.OtherPerson)
.WithMany() // no corresponding collection
.HasForeignKey(e => e.OtherPerson_ID)
.WillCascadeOnDelete(false);
如果您将第二个集合添加到Person
,请确保通过在第二个WithMany
内指定映射来正确更新映射。
请注意,并非强烈需要关闭两个关系的级联删除。只需为其中一个(在您的情况下,最有可能是第二个)关闭它就足够了。