EF6代码优先-如何在自引用TPH表中的删除时启用CASCADE或SET NULL?

时间:2018-09-07 13:19:44

标签: c# .net sql-server entity-framework-6 code-first

我正在使用TPH(按表分层结构)策略创建数据层次结构,并且在将TPH与表的自引用结合使用方面遇到了一些严重的问题。

为澄清起见:我正在使用EF6 Code First。

因此,事不宜迟,整个结构包含3个类:

  • 交易-抽象父项,
  • 债务:交易
  • 付款:交易

最简单的想法是,具有一定池(例如100 $)的债务可以包含多个付款,这些付款以后将总计并覆盖(例如20 $,50 $,30 $)。

public abstract class Transaction 
{
    [Key]
    public int Id { get; set; }

    public decimal MoneyPool { get; set; }

    public DateTime Date { get; set; }

}

public class Debt : Transaction
{
    public int DebtorId { get; set; }
    public Debtor Debtor { get; set; }

    public string Description { get; set; }


    public ICollection<Transaction> Payments { get; set; }

}

public class Payment : Transaction
{

    public int? DebtId { get; set; }
    public Debt Debt { get; set; }

}

从理论上讲,TPH是EF的默认继承实现模式,但出于我的考虑,我在OnModelCreating中手动添加了映射,以便在需要时可以进行一些更改。

protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Transaction>()
            .Map<Debt>(d => d.Requires("Discriminator").HasValue("Debt"));

        modelBuilder.Entity<Transaction>()
            .Map<Payment>(d => d.Requires("Discriminator").HasValue("Payment"));

        base.OnModelCreating(modelBuilder);
    }

现在,好消息是,获得/过账债务并对其进行约束性付款就可以了


问题

我希望能够删除债务并手动指定如何处理其子付款(付款)-可以级联删除它们或使FK属性无效。

我想检查初始化模型时EF为我设置的操作,因此在SQL Server Management Studio中运行sp_help Transactions,并注意到默认情况下,delete_action和update_action都设置为“ NO ACTION”如果是这样的自我表引用。

知道我试图手动更改它:

  1. 通过设置cascadeDelete参数,在创建原始层次结构表的迁移中
  2. 通过EF帮助程序方法删除初始外键并添加我自己的(启用了级联删除),
    1. 通过使用原始SQL进行上述操作。

所有这些结果都具有相同的错误:

  

在表“事务”上引入外键约束'FK_dbo.Transactions_dbo.Transactions_Debt_Id'可能会导致循环或多个级联路径。指定ON DELETE NO ACTION或ON UPDATE NO ACTION,或修改其他FOREIGN KEY约束。

起初有些令人惊讶,因为这正是我要尝试的完全-启用多个级联路径。但是由于某种原因,我不能。

我最后尝试做的是在覆盖的 OnModelCreating 中配置债务与付款之间的关系。

 modelBuilder.Entity<Transaction>()
            .Map<Payment>(d => d.Requires("Discriminator").HasValue("Payment"))
            .HasOptional(t => (t as Payment).Debt)
            .WithMany(t => (t as Debt).Payments)
            .WillCascadeOnDelete(true);

与此有关,我得到一个错误,指出(t为T)。属性不是指向属性的有效方法。但是,正如您可能已经知道的那样,如果没有演员表,我将根本无法访问conrete类的属性。

我完全陷入了困境。有谁能解决这个问题?我希望至少能够将delete_action设置为 cascade set null ,update_action的优先级较低,因为仅当有人更改主键时才会发生,无论如何,这是极不可能发生的。

0 个答案:

没有答案