陷阱~EF中的Update与Insert共用一个数据上下文

简介:

事情是这样的,有一个列表,里面有很多用户信息,可能会有重复的用户,将这个列表的用户插入到数据表中,如果用户已经存在,就更新这个用户的FillTimes 字段,让它加1,使用的底层ORM是entity frameworks4。

这是方法的大概内容

            var user_Account = iC_User_Account.Find(i => i.UserID == u.UserID);
            if (user_Account == null)
            {
                iRepository.Insert(new C_User_Account 
                {
                    AccountID = 1,
                    AddTime = rechargeTime,
                    BeginDate = rechargeTime,
                    EndDate = rechargeTime.AddYears(100),
                    FillTimes = 1,
                    Income = 0,
                    Incoming = 0,
                    LockMoney = 0,
                    Outgoings = card.CardValue,
                    Status = 1,
                    UserID = u.UserID,
                    UserType = 1,
                });
            }
            else
            {
            
                user_Account.FillTimes = user_Account.FillTimes ?? 0 + 1;
                iRepository.Update(user_Account);
            }

这个方法看似没有任何问题,当一个用户没有在表中存在,就insert,如果存在了,就update,这是再简单不过的逻辑了,然而,如果你的iRepository对象声明

放错了位置,可能问题就出来了,我们知道DbContext是有缓存的,当一个实体被提交后,它可能在缓存里还会存在,直到DbContext被dispose之后,它才会

消失,这就是说,如果insert与update使用的是同一个DbContext,就会出现一个异常,“不能在相同的对象上建立新实体”,而一般地,insert与update不能不同存在,这是我们可以想像的,而我们可能往往忽略了DbContext是否为一个,如果insert或者update之后,DbContext对象没有被销毁,那异常就会出现了。

而在本例中,iRepository的声明与实例化是在方法体外部完成的,而这个方法就是在被集合遍历时调用的,这时,你的iRepository里的DbContext对象就成了一个,在这个方法的生命周期时,你的数据上下文是一个,你的update操作也就出现问题了,呵呵。

//定义一个数据操作对象
var iRepository=new Repository<User>();

//供外部调用的更新用户列表的方法
public void UpdateUser(List<User> list)
{
  userList.ForEach(i=>{
     InsertOrUpdateUser(i);
 });
}

如果你的代码是这样写的话,那在遍历调用 InsertOrUpdateUser方法时,就有可能出现上面的异常了,呵呵!

正确的作法是将var iRepository=new Repository<User>();这句话移到InsertOrUpdateUser方法体里,问题就解决了。

本文转自博客园张占岭(仓储大叔)的博客,原文链接:陷阱~EF中的Update与Insert共用一个数据上下文,如需转载请自行联系原博主。

目录
相关文章
|
iOS开发
id的本质
id的本质
63 1
|
Python
禁止直接分配给多对多集的正面改用emails_for_help.set()
禁止直接分配给多对多集的正面改用emails_for_help.set()
|
SQL Oracle 网络协议
一条UPDATE从生到死的整个过程的深入解析
这是曾经Oracle原厂的一位兄弟问我的一个问题,后来也有些人问起这个问题: 用ORACLE内部原理描述以下过程: 1、sqlplus gyj/gyj@orcl 2、updatet_gyj set name='gyj1' where id=1; 3、commit; 4、exit 一看这个问题是不是灰常复杂,阿里系的童鞋特别喜欢用类似这样的题目面试人,从中可以快速的判断你是哪个级别的DBA(初级/中级/高级),在这个问题上我给大家抛砖迎玉,由于能力有限只能做简单解释,欢迎大家一起参与讨论并补充。嘿嘿!这是个很理论的东东希望对大家在处理实际问题的时候有一点点帮助。
一条UPDATE从生到死的整个过程的深入解析
|
数据库 缓存 SQL
EF 更新部分字段写法
原文:EF 更新部分字段写法 EF 更新部分字段写法 1、EF默认是查询出来,修改后保存; 2、设置不修改字段的IsModified为false,此方法不需要先从数据库查询出实体来(最优方法):        db.
3206 0
EF只更新变化的字段
原文:EF只更新变化的字段 摘要 在使用EF的时候,由于表字段较多,所以在更新的时候,想要只更新变化的字段,有没有办法呢? 解决办法 代码片段 public async Task UpdateAsync(T entity, List fieldNames) {...
1185 0
|
SQL
SQL更新id段之间的字段
SQL写得少, 写一次记一次。:)
1110 0