我的数据库中有两个表。表 USER 和表 USER_ADDRESSES
表 USER 有 UserID , UserName , HumanName
表 USER_ADDRESSES 有 UserAddresseID、UserID、Address
这两个表通过 UserID 外键关联。
我首先工作代码。POCO 就像我猜想的那样:
Public class User
{
Public guid UserID {get;set;}
Public string UserName {get;set;}
Public string HumanName {get;set;}
}
Public class UserAddress
{
Public guid UserAddressID {get;set;}
Public guid UserID {get;set;}
Public string Address {get;set;}
Public virtual User User {get;set;}
}
如果我发布一个用户,它会通过 EF 流入物理数据库 - 很酷
如果我使用正确分配为上述用户的 UserID 的 UserID 外键发布 UserAddress,则 userAddress 通过 EF 流入物理数据库 - 完美。
现在,当我正在学习这个主题时,我喜欢测试我知道会导致错误的场景……了解失败的原因通常会导致更好的理解(恕我直言)。
为此,我重复上述步骤。POST 一个用户,然后 POST 一个地址,但这次 Address.UserID 属性中的 GUID 为空,我知道这会导致 SQL 服务器出错,这次 EF 得到一个错误返回来自数据库并将我的控制器类中的错误显示为 DbUpdateException,然后我采取行动发送回 BadRequest ErrorResponse,这很好,除非现在我不能向数据库发布任何内容,如果我随后尝试发布新用户 EF在每个 POST 上引发 DbUpdateException。摆脱这种情况的唯一方法是停止调试 WebAPI 项目,终止 IISExpress 并重新启动一切。
我怀疑这与 dbset.Local 中跟踪的实体有关,而且我猜每次我调用 DataContext.SaveChanges() 时,EF 都会尝试提交它在其 bdset.Local 属性中的错误地址实体,从而阻止我进一步向数据库提交任何内容,直到整个项目重新启动并且各种 dbset.Local 集合被刷新。
好的,我明白了,在我的控制器类中,我可以通过在将对象提交到我的存储库/UnitOfWork 之前评估对象的各种属性来防止其中一些问题,从而防止它们首先进入 dbset.Local,也许有一些装饰我可以添加到我的 POCO 中,这样 ModelState.IsValid 如果 UserID == Guid.Empty 在 UserAddress 实体中返回 false ???. 但是 EF 应该能够从 DB 引发的错误中恢复,这样如果在 SQL 服务器上运行时 INSERT 语句失败,EF 应该从其跟踪对象的本地缓存中删除有故障的实体。从而防止整个系统需要完全重新启动。这样做的结果是,如果我对其他非关键字段有独特的限制,在尝试提交实体之前,我必须查询数据库以确保数据库中没有记录会导致抛出 DBUdateException,这种方法对我来说似乎效率低下。我宁愿接受错误并将其返回给客户以供他们考虑。
现在也许我有责任在发生 DbUpdateException 时采取措施从 dbset.Local 集合或类似集合中删除故障实体。如果是这种情况,我该怎么办?
当我一直在写这篇文章时,我想知道:EF 是否应该无法从 DBUdateExceptions 中恢复!?无需重新启动 IIS。或者我是否应该毫无限制地构建我的数据库,并允许客户将任何旧垃圾放在那里。我认为 EF 实体跟踪应该尊重 db 约束并首先防止有故障的实体进入 dbset。
请指导我从 DBUpdateException 中恢复的正确方法?