gpt4 book ai didi

c# - EF Core 删除同一张表上的一对一关系

转载 作者:行者123 更新时间:2023-11-30 15:15:23 25 4
gpt4 key购买 nike

模型与自身有可选关系

public class Item
{
public Guid Id { get; set; }
public string Description { get; set; }
public Guid StockId { get; set; }

// optionally reference to another item from different stock
public Guid? OptionalItemId { get; set; }

public virtual Item OptionalItem { get; set; }
}

在 DbContext 模型中配置如下:

protected override void OnModelCreating(ModelBuilder builder)
{
builder.Entity<Item>().HasOne(item => item.OptionalItem)
.WithOne()
.HasForeignKey<Item>(item => item.OptionalItemId)
.HasPrincipalKey<Item>(item => item.Id)
.IsRequired(false)
}

我想通过在使用新项目更新 Stock 之前删除现有项目来用新项目替换现有项目。

// Given Stock contains only new items
public void Update(Stock stock)
{
using (var context = CreateContext())
{
// Remove old items
var oldItems = context.Items
.Where(item => item.StockId == stock.Id)
.Select(item => new Item { Id = item.Id })
.ToList();
context.Items.RemoveRange(oldItems);

// Remove optional items from another stock
var oldOptionalItems = context.Items
.Where(item => item.StockId == stock.RelatedStock.Id)
.Select(item => new Item { Id = item.Id })
.ToList();
context.Items.RemoveRange(oldOptionalItems);

context.Stocks.Update(stock);
context.SaveChanges();
}
}

问题是当 Update 方法执行时,行 context.SaveChanges() 抛出异常:

SqlException: The DELETE statement conflicted with the SAME TABLE REFERENCE constraint "FK_Item_Item_OptionalItemId". The conflict occurred in database "local-database", table "dbo.Item", column 'OptionalItemId'.

我发现另一个有类似问题的问题:The DELETE statement conflicted with the SAME TABLE REFERENCE constraint with Entity Framework .
但看起来所有答案都与 Entity Framework (而非 EF Core)相关。

我尝试将删除行为更改为
- .OnDelete(DeleteBehavior.Cascade)

- .OnDelete(DeleteBehavior.SetNull)
但是在向数据库应用迁移期间,这两种行为都会在下面抛出异常。

Introducing FOREIGN KEY constraint 'FK_Item_Item_OptionalItemId' on table 'Item' may cause cycles or multiple cascade paths.
Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.

最佳答案

像往常一样,当您不允许使用级联删除选项时(顺便说一句,SqlServer 限制,某些数据库如 Oracle 没有此类问题),您需要(递归地)在删除记录之前删除相关数据。

它可以一个接一个或按级别完成(更少的 SQL 命令,但可能使用大的 IN PK 列表)。相关数据也可以使用基于 CTE 的 SQL 来确定——这是最有效但与数据库无关的方式。

下面的方法实现了第二种方法:

static void DeleteItems(DbContext context, Expression<Func<Item, bool>> filter)
{
var items = context.Set<Item>().Where(filter).ToList();
if (items.Count == 0) return;
var itemIds = items.Select(e => e.Id);
DeleteItems(context, e => e.OptionalItemId != null && itemIds.Contains(e.OptionalItemId.Value));
context.RemoveRange(items);
}

并且可以像这样在您的代码中使用:

using (var context = CreateContext())
{
// Remove old items
DeleteItems(context, item => item.StockId == stock.Id);

// Remove optional items from another stock
DeleteItems(context, item => item.StockId == stock.RelatedStock.Id);

// The rest...
}

关于c# - EF Core 删除同一张表上的一对一关系,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52136521/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com