entity-framework - 如何删除与同一张表具有 1:1 关系的行?
问题描述
我使用 Entity Framework Core,我有一个表:
public class BlogComment
{
public int Id { get; set; }
public BlogPost Post { get; set; }
[StringLength(100)]
public string AuthorName { get; set; }
[StringLength(254)]
public string AuthorEmail { get; set; }
public bool SendMailOnReply { get; set; }
[StringLength(2000)]
public string Content { get; set; }
public DateTime CreatedTime { get; set; }
public int? ReplyToId { get; set; }
public BlogComment ReplyTo { get; set; }
}
由此,EFC 生成下表:
CREATE TABLE [dbo].[BlogComment] (
[Id] INT IDENTITY (1, 1) NOT NULL,
[AuthorEmail] NVARCHAR (254) NULL,
[AuthorName] NVARCHAR (100) NULL,
[Content] NVARCHAR (2000) NULL,
[CreatedTime] DATETIME2 (7) NOT NULL,
[PostId] INT NULL,
[ReplyToId] INT NULL,
[SendMailOnReply] BIT NOT NULL,
CONSTRAINT [PK_BlogComment] PRIMARY KEY CLUSTERED ([Id] ASC),
CONSTRAINT [FK_BlogComment_BlogPost_PostId] FOREIGN KEY ([PostId]) REFERENCES [dbo].[BlogPost] ([Id]),
CONSTRAINT [FK_BlogComment_BlogComment_ReplyToId] FOREIGN KEY ([ReplyToId]) REFERENCES [dbo].[BlogComment] ([Id])
);
GO
CREATE NONCLUSTERED INDEX [IX_BlogComment_PostId]
ON [dbo].[BlogComment]([PostId] ASC);
GO
CREATE UNIQUE NONCLUSTERED INDEX [IX_BlogComment_ReplyToId]
ON [dbo].[BlogComment]([ReplyToId] ASC) WHERE ([ReplyToId] IS NOT NULL);
有些评论是作为对另一个评论的回复发送的,但不是全部。删除原评论后,回复变为普通评论。因此,按照本教程,配置看起来是这样的:
modelBuilder.Entity<BlogComment>()
.HasOne(p => p.ReplyTo)
.WithOne()
.HasForeignKey<BlogComment>(c => c.ReplyToId)
.IsRequired(false)
.OnDelete(DeleteBehavior.SetNull);
删除方法很简单:
var comment = await context.BlogComment.Include(c => c.ReplyTo).SingleAsync(m => m.Id == id);
context.BlogComment.Remove(comment);
await context.SaveChangesAsync();
但是我不能运行它,我得到一个错误:
System.Data.SqlClient.SqlException:DELETE 语句与 SAME TABLE REFERENCE 约束“FK_BlogComment_BlogComment_ReplyToId”冲突。
我怎样才能解决这个问题?
解决方案
在评论中结束对话:
首先,自引用是一个 1:n 关联:
modelBuilder.Entity<BlogComment>()
.HasOne(p => p.ReplyTo)
.WithMany(c => c.Replies)
.HasForeignKey(c => c.ReplyToId)
.IsRequired(false)
.OnDelete(<we'll get to that>);
所以,只是为了方便,BlogComment
现在也有属性了
public ICollection<BlogComment> Replies { get; set; }
但是,我无法使用
.OnDelete(DeleteBehavior.SetNull);
它给了我
在表“BlogComments”上引入 FOREIGN KEY 约束“FK_BlogComments_BlogComments_ReplyToId”可能会导致循环或多个级联路径。
这是我们只能接受的 Sql Server 限制,无法回避。获得所需级联行为的唯一方法是
.OnDelete(DeleteBehavior.ClientSetNull);
这是:
对于 DbContext 跟踪的实体,依赖实体中的外键属性的值设置为 null。这有助于在跟踪实体图时将它们保持在一致状态,以便可以将完全一致的图写入数据库。(...) 这是可选关系的默认设置。
即:客户端执行 SQL 以使外键值无效。但是应该跟踪子记录。要删除BlogComment
父级,删除操作应如下所示:
using (var db = new MyContext(connectionString))
{
var c1 = db.BlogComments
.Include(c => c.Replies) // Children should be included
.SingleOrDefault(c => c.Id == 1);
db.BlogComments.Remove(c1);
db.SaveChanges();
}
如您所见,您不必设置ReplyToId = null
,这是 EF 负责的事情。
推荐阅读
- python - python中两个列表中的精确字符串匹配
- c# - 为什么SqliteConnection 不打开连接?
- function - 在类中调用反应本机函数
- javascript - 右键单击时在 div 菜单的标题中显示所选几何图形的名称
- ansible - Ansible 处理程序被赋予启动特定服务的任务。如果服务在被调用时已经启动,Ansible 处理程序会做什么?
- ffmpeg - 电子包装器的电子包装错误
- javascript - Javascript:优化 iFrame 的重新排序,如 DOM 节点
- android - 重启应用后Zxing条码扫描器不工作
- android - 带有 GridLayout 的 ScrollView 不会从顶部开始
- react-native - 在 React Native 中的 Icon 中创建一个包含名字和姓氏首字母的图标