EF6存储错误的解决

最近使用EF的时候,前端程序员反应数据库运行一旦时间会发生一个存储错误,查看日志后,发现是EF抛出的异常,具体异常消息为“The object cannot be deleted because it was not found in the ObjectStateManager”

经过调试,发现是对EF6中的DbSet调用RemoveRange函数时抛出的异常。让人很头痛,也没有精力去研究EF的源代码来准确的定位错误产生的原因,然后ObjectStateManager又是EF中的什么东西?看似是一个棘手,一时无法解决的问题。

项目马上就要进行上线更新,所以静下心来分析。仔细阅读错误日志,可以发现,该异常应该是在Delete某个object时产生的,而且我们调试下来也是在RemoveRange这个函数,那么可以假定应该是我们调用该函数时,传递的,要删除的记录数据出了问题。而且是因为找不到要删除的数据才报的错。

断点,监视数据,发现我们传递进去要删除的数据有4条,查看了具体的数据后,发现4条数据的值居然一模一样。那马上联想到,我们在业务逻辑上存在错误,是否反复将同一记录多次添加到待删除的队列中了。经过一番排查,确实发现了业务逻辑上存在问题,有将同一记录多次删除的情况,修改。

运行后,错误依旧。这下又迷茫了,还是继续断点调试,发现这时RemoveRange中并没有重复的数据记录。那为何还是会报这个异常呢?在对比异常消息,作出进一步的假设,会不会说,这条待删除的数据,数据库中本身就没有?

我们抛出异常的业务逻辑的行为,是一段处理玩家申请的逻辑。在申请到来时保存申请记录,一旦申请处理后,删除该记录。服务器定时存储数据库。这时突然联想到了两点,首先EF的对数据库的操作,其本质还是执行的SQL语句,其次,其对数据库的改变,必须经过SaveChanges才能最终反应在数据库中。我们的业务逻辑,在保存申请记录时,调用的DbSet的Add函数,删除时调用DbSet的Remove函数,然后才是SaveChanges。如果DbSet是普通的集合,这没有问题。但是如果Add,Remove其最终执行的是Sql语句的话,当Add执行后,还没有SaveChanges(相当于Sql语句中Commit),那么这条记录可能并没有真正存在于数据库中,那么下面的Remove自然就找不到该记录,从而产生异常。

所以从我们的业务逻辑看,如果处理完申请,该记录被删除,其实相当于是取消了刚才保存的记录。也就是不对该记录进行Add操作

总结

对DbSet进行操作时,如果是操作数据库已有的记录,那么没有任何问题。而如果是操作数据库还没有的数据,只是缓冲到DbSet中的数据,我们要注意,如果是删除操作,实际是撤销前面的添加操作,如果是修改操作,要找到先前添加到DbSet缓存中的记录进行操作,而不是另起一条操作记录。要明确,没有SaveChanges时,这些数据在数据库中并不存在

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章