【问题标题】:EF Core - Cascade deletes happening the other way aroundEF Core - 级联删除以相反的方式发生
【发布时间】:2021-11-14 17:16:59
【问题描述】:

我有一个简单的 EF Core 模型,其中包含两个实体,位置和地址,其中位置必须始终具有地址。

实体及其配置如下:

public class Location {
    [Key]
    public int Id { get; set; }
    public string Name { get; set; }
    public int AddressId { get; set; }
    [ForeignKey("AddressId")]
    public virtual Address Address { get; set; }
}
public class Address {
    public virtual int AddressId { get; set; }
    public string LineOne { get; set; }
    public string LineTwo { get; set; }
    public string City { get; set; }
    public string Country { get; set; }
    public string ZipPostCode { get; set; }
    public string State { get; set; }
    public string LandlinePhone { get; set; }
    public string MobilePhone { get; set; }
}

// Context configuration
...
protected override void OnModelCreating(ModelBuilder modelBuilder) {
...
modelBuilder.Entity<Location>().HasOne(l => l.Address).WithOne().OnDelete(DeleteBehavior.Cascade);
...
}
...

注意:地址实体没有对位置的引用。

使用上述配置,删除位置应删除其地址,但删除地址应导致引用完整性错误。使用 EF InMemory 数据库通过单元测试尝试上述操作会产生意想不到的结果:

    [Test]
    public void DeleteAddressShouldNotDeleteLocation() {
        var address = new Address();
        var location = new Location() {Address = address};
        _context.Locations.Add(location);
        _context.SaveChanges();

        // Delete the address added above
        _context.Addresses.Remove(_context.Addresses.Single());
        _context.SaveChanges();

        Assert.AreEqual(1, _context.Locations.Count()); --> ALWAYS FAILS AS THE LOCATION IS CASCADE DELETED
    }

这也发生在我们的生产服务器 (Azure SQL) 上,因此它不应该是 EF Core 的问题。

EF 将地址删除级联到 Location 有什么原因吗?

【问题讨论】:

    标签: c# ef-core-3.1


    【解决方案1】:

    使用上述配置,删除位置应该会删除其地址,但删除地址会导致引用完整性错误

    否定的。每个关系(除了多对多)都有principaldependent(参见Relationships - Definitions of terms)。级联删除从主体(引用)到依赖(引用)。如果禁用了级联删除,则如果有对它的引用,则无法删除主体。

    那么,在您的案件中,谁是受抚养人?依赖者始终是具有 FK 引用的人,即 Location,因此您正在经历的行为。

    如果您想换一种方式,请从Location 中删除AddressId FK 并将LocationId FK 添加到Address(或通过使@987654327 配置/使用所谓的“共享主键关联” @PK 也是 FK)。

    但请注意,没有任何关系设计可以满足您的所有要求。最接近的(将满足 3 个中的 2 个)是使用 DeleteBehavior.Restrict 保留当前设计。这边

    1. 位置必须始终有一个地址 - 满意。
    2. 删除地址会导致引用完整性错误 - 满足
    3. 删除位置应删除其地址 - 不满意,也不能,因为该位置不拥有该地址。

    【讨论】:

    • 感谢您的回答。哦,我明白你的意思,所以在我的情况下,主要是地址。我认为解决方法是强制地址不删除该位置,对吗?
    • 是的,确实是 (DeleteBehavior.Restrict)。这将最接近您的要求 - 将满足 3 个中的 2 个。仅“删除位置应删除其地址”不会发生,因为位置不拥有该地址。
    【解决方案2】:

    .OnDelete(DeleteBehavior.Restrict) 试试 - 违反直觉,但适用于我的项目。
    可以把它想象成“如果有地址,不要让地址被删除”。

    此关系的附加 .IsRequired() 将强制使用一个地址 - 正如您在问题中所述(位置始终有一个地址)。

    【讨论】:

    • 谢谢。我只是尝试了你的建议,没有运气。地址仍在删除位置实体:(
    • 只是为了确定,这可能很明显 - 如果您使用 ef 代码优先 - 您是否回滚了将您的配置设置为创建 + 应用的新迁移的迁移,具有 Restrict 行为?跨度>
    • 我实际上有使用 EF InMemory Db 检查级联删除的单元测试
    • 在使用 InMemory 进行测试时,this 是否可能是原因?
    • 可能是这样。它适用于其他启用了级联删除的关系
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-19
    • 2018-08-29
    • 2018-03-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多