实体框架核心:读取和删除数据之间的事务

时间:2018-09-12 12:11:29

标签: c# .net-core entity-framework-core

我在.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不会一次调用就删除房屋,而是会为房屋中的每个房间调用删除房间(并希望房屋与最后一个房间一起自动删除)。这会导致问题。呼叫紧接彼此,每个房间都加载房屋实体,检查它是否是最后一个房间,识别其他房间,房间被删除,空房子仍然存在。

这是否有可能解决(因此,空房子不会保留),例如有交易吗?

2 个答案:

答案 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的文档