Entity Framework Code First - 对不同父表的多个 FK
Entity Framework Code First - Multiple FKs to different parent tables
看起来像一个 "yet another EF multiple FK" 问题,但请继续阅读。我有以下要求:
- 一个"Monitor"可以有零个或多个"Notifier"
- 一个"Monitor"可以有零个或多个"Setting"
- 一个"Notifier"可以有零个或多个"Setting"
因此,删除 "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; }
}
}
在您的 Setting
和 Notifier
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 使用。如果您想要 MonitorId
和 NotifierId
,也可以将其拆分。这完全取决于您的数据模型。
编辑:
如果您需要 MonitorId
和 NotifierId
.
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; }
}
看起来像一个 "yet another EF multiple FK" 问题,但请继续阅读。我有以下要求:
- 一个"Monitor"可以有零个或多个"Notifier"
- 一个"Monitor"可以有零个或多个"Setting"
- 一个"Notifier"可以有零个或多个"Setting"
因此,删除 "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; }
}
}
在您的 Setting
和 Notifier
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 使用。如果您想要 MonitorId
和 NotifierId
,也可以将其拆分。这完全取决于您的数据模型。
编辑:
如果您需要 MonitorId
和 NotifierId
.
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; }
}