我在.NET Core REST API中遇到实体框架核心的问题。
示例数据模型:
饭厅(ID,名称) 桌房(id,houseId,名称)
一间房子可以有多个房间,一个房间只能在一个房子里。
我删除房间时出现问题。每次用户请求删除房间时,我都会检查房间是否是房屋中的最后一个,是否也是最后一个,我也会删除(空)房屋。
Room room = dbContext.Room
.Include(r => r.House).ThenInclude(h => h.Rooms)
.Where(r => r.id == id)
.SingleOrDefaultAsync();
if (room.House.Rooms.Count > 1) {
// other rooms are present
dbContext.Room.Remove(room);
} else {
// delete house if it is the last room
dbContext.House.Remove(room.House);
}
dbContext.SaveChanges();
问题在于,我们的UI不会一次调用就删除房屋,而是会为房屋中的每个房间调用删除房间(并希望房屋与最后一个房间一起自动删除)。这会导致问题。呼叫紧接彼此,每个房间都加载房屋实体,检查它是否是最后一个房间,识别其他房间,房间被删除,空房子仍然存在。
这是否有可能解决(因此,空房子不会保留),例如有交易吗?
答案 0 :(得分:2)
是,不是。您可以将其包装到一个事务中,这很简单。
https://docs.microsoft.com/en-us/ef/core/saving/transactions
显示方法。
您基本上只是创建一个事务:
使用(var transaction = context.Database.BeginTransaction())
或者,您可以在DbConnection上使用DbTransaction。相同的链接。
但是您的代码组织得很糟糕。
每个房间都加载房屋实体,检查它是否是最后一个房间,识别其他房间 房间,房间被删除,空房子仍然存在。
听起来像有人完全在一些不错的存储库反模式后面提取了db,然后那个(不是事务)再次咬住了你。可能每个删除的房间都使用一个单独的存储库-繁荣,交易无济于事。
重构时间。
答案 1 :(得分:0)
最好的解决方案可能是创建一个单独的新方法来删除房屋,以便一次调用即可处理整个房屋。
如果确实存在某些问题使您无法完成DeleteHouse方法,则可以通过锁定解决问题。我认为您的根本问题是线程竞争条件。在您的删除房间代码中添加锁以解决该问题。
lock(_deleteRoomLock)
{ \\Your delete room code }
此模式的缺点是,最终您将在服务器端代码中创建一个删除房间的瓶颈。
链接到有关锁定https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/lock-statement的文档