Entity Framework Code First - 对不同父表的多个 FK

Entity Framework Code First - Multiple FKs to different parent tables

看起来像一个 "yet another EF multiple FK" 问题,但请继续阅读。我有以下要求:

因此,删除 "Monitor" 将删除它的 "Setting" 和 "Notifiers"。此外,由于 "Notifier" 可能有零个或多个设置,因此也应删除相关的 "Setting"。

我创建了以下模型,但遇到了著名的“...可能导致循环或多个级联路径”错误。

最接近的答案是 Entity Framework Cascading Delete,但它使用数据库优先方法。

任何人都可以建议一种解决方法来启用对上述模型的级联删除吗?

这是我的模型:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data.Entity;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace Testbed
{
    public class Monitor
    {
        public int Id { get; set; }
        [Column(TypeName = "varchar")]
        [MaxLength(255)]
        public string Type { get; set; }
        [Column(TypeName = "varchar")]
        [MaxLength(20)]
        public string RunFrequency { get; set; }
        public List<Setting> Settings { get; set; }
        public List<Notifier> Notifiers { get; set; }
    }

    public class Setting
    {
        public int Id { get; set; }
        [MaxLength(255)]
        [Column(TypeName = "varchar")]
        public string Name { get; set; }
        [MaxLength(512)]
        public string Value { get; set; }
        public bool IsPassword { get; set; }
    }

    public class Notifier
    {
        public int Id { get; set; }
        [MaxLength(255)]
        [Column(TypeName = "varchar")]
        public string Name { get; set; }
        public List<Setting> Settings { get; set; }

    }
}

在您的 SettingNotifier classes 中,您必须添加一些属性以允许这种关系。

public class Setting
{
    public int Id { get; set; }
    [MaxLength(255)]
    [Column(TypeName = "varchar")]
    public string Name { get; set; }
    [MaxLength(512)]
    public string Value { get; set; }
    public bool IsPassword { get; set; }

    //Add these properties
    public int ForeignId{ get; set; }
    public virtual Monitor Monitor { get; set; }
    public virtual Notifier Notifier { get; set; }
}

public class Notifier
{
    public int Id { get; set; }
    [MaxLength(255)]
    [Column(TypeName = "varchar")]
    public string Name { get; set; }
    public List<Setting> Settings { get; set; }

    //Add these properties
    public int MonitorId { get; set; }
    public virtual Monitor Monitor { get; set; }

}

现在您已经启用了关系,您将需要添加映射。这可以在您的 EntityModel 或您的映射 class 中完成,如果您将它们分开。

modelBuilder.Entity<Setting>()
    .HasOptional(e => e.Monitor) //Could be .HasRequired()
    .WithMany(e => e.Settings)
    .HasForeignKey(e => e.ForeignId)
    .WillCascadeOnDelete(true);

modelBuilder.Entity<Setting>()
    .HasOptional(e => e.Notifier) //Could be .HasRequired()
    .WithMany(e => e.Settings)
    .HasForeignKey(e => e.ForeignId)
    .WillCascadeOnDelete(true);

modelBuilder.Entity<Notifier>()
    .HasRequired(e => e.Monitor) //Could be .HasOptional()
    .WithMany(e => e.Notifiers)
    .HasForeignKey(e => e.MonitorId)
    .WillCascadeOnDelete(true);

这种设置方式总是会导致问题。多个 table 正在使用您的 Settings table。在我的示例中,我在 Settings 中创建了一个外键,供其他两个 table 使用。如果您想要 MonitorIdNotifierId,也可以将其拆分。这完全取决于您的数据模型。

编辑: 如果您需要 MonitorIdNotifierId.

modelBuilder.Entity<Setting>()
    .HasOptional(e => e.Monitor) //Could be .HasRequired()
    .WithMany(e => e.Settings)
    .HasForeignKey(e => e.MonitorId)
    .WillCascadeOnDelete(true);

modelBuilder.Entity<Setting>()
    .HasOptional(e => e.Notifier) //Could be .HasRequired()
    .WithMany(e => e.Settings)
    .HasForeignKey(e => e.NotifierId)
    .WillCascadeOnDelete(true);

您还必须将这些属性添加到设置 class。

public class Setting
{
    public int MonitorId { get; set; }
    public int NotifierId { get; set; }
}