[英]Remove cascade on delete from a single path
跟踪我的数据模型。 我删除了所有不重要的注释,以使其简洁明了。
public class Bubble
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<Level> Levels { get; set; }
}
public class Level
{
public int Id { get; set; }
public int BubbleId { get; set; }
[ForeignKey("ParentLevel")]
public int? LevelId { get; set; }
public string Name { get; set; }
public Level ParentLevel { get; set; }
public Bubble Bubble { get; set; }
public ICollection<Level> Levels { get; set; }
public ICollection<Item> Items { get; set; }
}
public class Item
{
public int Id { get; set; }
public int LevelId { get; set; }
public string Name { get; set; }
public Level Level { get; set; }
}
如果我这样创建它,我将得到错误:
在表“ Item”上引入FOREIGN KEY约束“ FK_dbo.Item_dbo.Level_LevelId”可能会导致循环或多个级联路径。 指定ON DELETE NO ACTION或ON UPDATE NO ACTION,或修改其他FOREIGN KEY约束。 无法创建约束或索引。 查看先前的错误。
如果我添加此代码,则数据库创建有效:
modelBuilder.Entity<Item>()
.HasRequired(i => i.Level)
.WithMany(l => l.Items)
.HasForeignKey(i => i.LevelId)
.WillCascadeOnDelete(false);
但是当我删除气泡时,我得到了这个错误:
SqlException:DELETE语句与REFERENCE约束“ FK_dbo.Item_dbo.Level_LevelId”冲突。 数据库“ MvBubbles1”的表“ dbo.Item”的列“ LevelId”中发生了冲突。 该语句已终止。
所以我相信问题是,级别是自引用的。 因为我有很多一对多的关系,并且删除和层叠操作在除Level和Item之间的所有地方都可以使用,所以唯一的区别是在可行的情况下父级不是自引用的。 我相信我只需要删除一个级联路径,但此刻我不知道如何执行此操作,而在不禁用删除功能的情况下,问题出在哪里,但我不想禁用它。
删除代码:
db.Bubbles.Remove(bubble);
db.SaveChanges();
级联关闭时无法删除气泡的原因是,您仍然具有要删除气泡的外键级别。
此外,假设您要删除气泡2。气泡2具有最高级别20。
气泡3的级别为21,是级别20的子级别。
气泡4具有级别22,它是级别21的子级别。
如果删除气泡2,是否应删除气泡3和4的水平?
假设您的软件没有这些特性:没有循环的关卡引用,并且所有关卡都来自同一Bubble。
您可以在删除“关卡”和“气泡”之前使要删除的“气泡”的所有关卡的所有LevelIds无效:
// we want to remove Bubble 2
var levelsToRemove = dbContext.Levels.Where(level => level.BubbleId == 2).ToList();
// nullify all levelIds:
foreach (var levelToRemove in levelsToRemove)
{
levelToRemove.LevelId = null;
}
// TODO: maybe we need an extra SaveChanges
// Remove the Levels and the Bubble:
dbContext.Levels.RemoveRange(levelsToRemove);
var bubbleToRemove = dbContext.Find(2); // TODO: exception if not found
dbContext.Bubbles.Remove(bubbleToRemove);
dbContext.SaveChanges();
您的代码必须防止循环引用和带有Levels的Bubbles属于其他Bubbles的Levels子级别,这应该使您知道您的数据库不够规范。
考虑给您的LevelCollection。 这将是一对零或一对的关系,或者如果所有Bubble 2的所有关卡都有若干共同点,请考虑将这些东西放到LevelCollection中,并让您的Bubble拥有零个或多个LevelCollection(一对多)。 )。
每个LevelCollection都完全属于一个Bubble。 LevelCollection具有零个或多个级别。
现在可以保证,如果LevelCollection 42属于Bubble 2,则LevelCollection 42的所有级别都属于Bubble2。您可以从级别中删除外键BubbleId。
这不会阻止循环的关卡引用,但会阻止一棵树的关卡属于不同的气泡
通常,如果您与一所学校有一对多关系,并且有许多学生,则在删除学校时,您还希望自动删除其所有学生。 启用层叠时,实体框架将首先删除所有带有外键的项目,这些外键指向您要移动的项目,然后再删除您的项目。
气泡和色阶无法自动完成
让我们添加一些气泡和水平
Id | Name
Add Bubble with name A => 1 | A
Id | BubbleId | LevelId
Add Level without Parent for Bubble 1 => 10 | 1 | null
Add sub Level of Level 10 Parent for Bubble 2 => 11 | 1 | 10
Now give Level 10 a new LevelId => 10 | 1 | 11
好的,级联打开,让我们删除Bubble 1。
在实体框架可以执行此操作之前,它必须删除所有具有Bubble 1外键的内容。因此,我们需要先删除10级,而不能删除,因为我们必须先删除11级。 但是,无法删除第11级,因为无法删除第10级,依此类推
我们已经制作了一个小圆圈,但是您可以想象一下,如果您拥有一个具有1000个色阶的圆圈,将会发生什么。
您的代码可能会阻止您创建一个圆,但是实体框架不能阻止您这样做。
另一个问题:假设气泡2的级别为20。级别20是级别21的子级别,而级别21具有到气泡1的外键。如果删除气泡1,则气泡2的级别会发生什么? 有人可能会说:它变成了泡泡2的最高等级,其他人可能会说:不,泡泡2失去了他的等级。 实体框架无法检测到您想要的内容,因此您必须自己进行操作并关闭级联。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.