C# 实体框架核心代码优先:多对多关系上的级联删除

C# 实体框架核心代码优先:多对多关系上的级联删除,c#,entity-framework,ef-code-first,code-first,entity-framework-core,C#,Entity Framework,Ef Code First,Code First,Entity Framework Core,我正在从事一个ASP.NET MVC 6项目,该项目具有Entity Framework Core(版本“EntityFramework.Core”:“7.0.0-rc1-final”),由SQL Server 2012 express DB支持 我需要在个人实体和地址实体之间建立多对多关系模型。 根据指南,我使用PersonAddressjoin表实体对其进行建模,因为这样我可以存储一些额外的信息 我的目标是通过以下方式设置我的系统: 如果删除了Person实例,则必须删除所有相关的Pers

我正在从事一个ASP.NET MVC 6项目,该项目具有Entity Framework Core(版本
“EntityFramework.Core”:“7.0.0-rc1-final”
),由SQL Server 2012 express DB支持

我需要在
个人
实体和
地址
实体之间建立多对多关系模型。 根据指南,我使用
PersonAddress
join表实体对其进行建模,因为这样我可以存储一些额外的信息

我的目标是通过以下方式设置我的系统:

  • 如果删除了
    Person
    实例,则必须删除所有相关的
    PersonalAddress
    实例。它们引用的所有
    地址
    实例也必须删除,前提是它们与其他
    PersonalAddress
    实例不相关
  • 如果删除了
    PersonalAddress
    实例,则只有当它与其他
    PersonalAddress
    实例不相关时,才必须删除与其相关的
    Address
    实例。所有
    Person
    实例都必须生存
  • 如果删除了
    地址
    实例,则必须删除所有相关的
    角色地址
    实例。所有
    Person
    实例都必须生存
我认为大部分工作必须在
地址
之间的多对多关系中完成,但我也希望能写出一些逻辑。我将不讨论这一部分。我感兴趣的是如何配置我的多对多关系

以下是当前的情况

这是
个人
实体。请注意,此实体与其他辅助实体具有一对多关系

public class Person
{
    public int Id {get; set; } //PK
    public virtual ICollection<Telephone> Telephones { get; set; } //navigation property
    public virtual ICollection<PersonAddress> Addresses { get; set; } //navigation property for the many-to-many relationship
}
这是
PersonalAddress
实体

public class Address
{
    public int Id { get; set; } //PK
    public int CityId { get; set; } //FK
    public City City { get; set; } //navigation property
    public virtual ICollection<PersonAddress> People { get; set; } //navigation property
}
public class PersonAddress
{
    //PK: PersonId + AddressId
    public int PersonId { get; set; } //FK
    public Person Person {get; set; } //navigation property
    public int AddressId { get; set; } //FK
    public Address Address {get; set; } //navigation property
    //other info removed for simplicity
}
这是描述所有关系的
DatabaseContext
实体

public class DataBaseContext : DbContext
{
    public DbSet<Person> People { get; set; }
    public DbSet<Address> Addresses { get; set; }

    protected override void OnModelCreating(ModelBuilder builder)
    {            
        //All the telephones must be deleteded alongside a Person.
        //Deleting a telephone must not delete the person it refers to.
        builder.Entity<Person>()
            .HasMany(p => p.Telephones)
            .WithOne(p => p.Person);

        //I don't want to delete the City when I delete an Address
        builder.Entity<Address>()
            .HasOne(p => p.City)
            .WithMany(p => p.Addresses)
            .IsRequired().OnDelete(Microsoft.Data.Entity.Metadata.DeleteBehavior.Restrict);

        //PK for the join entity
        builder.Entity<PersonAddress>()
            .HasKey(x => new { x.AddressId, x.PersonId });

        builder.Entity<PersonAddress>()
            .HasOne(p => p.Person)
            .WithMany(p => p.Addresses)
            .IsRequired();

        builder.Entity<PersonAddress>()
            .HasOne(p => p.Address)
            .WithMany(p => p.People)
            .IsRequired();
    }
}
至于我的读数,避免
.Include()
将让数据库处理最终的
级联
删除。很抱歉,我不记得这个概念是在哪里被澄清的

如果我运行这段代码,我可以使用。当我想用上述代码测试删除一个
Person
实体时,我得到以下异常:

The DELETE statement conflicted with the REFERENCE constraint "FK_PersonAddress_Person_PersonId". The conflict occurred in database "<dbName>", table "<dbo>.PersonAddress", column 'PersonId'.
The statement has been terminated.
DELETE语句与引用约束“FK\u PersonAddress\u PersonId”冲突。冲突发生在数据库“”的表“.PersonalAddress”列“PersonId”中。
声明已终止。
我在
DatabaseContext.OnModelCreating
方法中测试了几个关系设置,但没有任何运气

最后,这是我的问题。根据前面描述的目标,我应该如何配置我的多对多关系,以便从我的应用程序中正确删除
人及其相关实体


谢谢大家。

首先,我看到您已经设置了城市地址
删除行为的关系。限制
,然后您说: “//我不想在删除地址时删除城市”。
但是您不需要在这里进行限制,因为即使使用
DeleteBehavior.Cascade
City也不会被删除。 你看得不对。 这里所做的
Cascade
是当一个城市被删除时,属于它的所有地址也被删除。 这种行为是合乎逻辑的

其次,你的多对多关系很好。 删除Person时,由于级联,PersonalAddress表中的链接将自动删除。 如果您还想删除仅与此人连接的地址,则必须手动删除。 实际上,在删除此人之前,您必须先删除这些地址,以便知道要删除什么。
因此,逻辑应该如下:
1.查询PersonalAddress的所有记录,其中
PersonId=person.Id

2.其中,只有那些在PersonalAddress表中AddressId只出现一次的,并从Person表中删除它们。
3.现在删除此人。

您可以直接在代码中执行此操作,或者如果希望数据库为您执行此操作,可以使用以下函数为步骤2创建触发器: 当即将删除PersonalAddress中的行时,请检查该PersonalAddress表中是否没有具有相同AddressId的行,在这种情况下,请将其从Address表中删除

更多信息请点击此处:

The DELETE statement conflicted with the REFERENCE constraint "FK_PersonAddress_Person_PersonId". The conflict occurred in database "<dbName>", table "<dbo>.PersonAddress", column 'PersonId'.
The statement has been terminated.