首页 新闻 搜索 专区 学院

EF中重复操作同一个表的同一条数据时出错。

0
悬赏园豆:100 [已解决问题] 解决于 2015-02-12 16:43

附加类型“penson”的实体失败,因为相同类型的其他实体已具有相同的主键值。在使用 "Attach" 方法或者将实体的状态设置为 "Unchanged" 或 "Modified" 时如果图形中的任何实体具有冲突键值,则可能会发生上述行为。这可能是因为某些实体是新的并且尚未接收数据库生成的键值。在此情况下,使用 "Add" 方法或者 "Added" 实体状态跟踪该图形,然后将非新实体的状态相应设置为 "Unchanged" 或 "Modified"。


context.Entry<Penson>(item).State = EntityState.Modified;   //出错位置。 
      int result = context.SaveChanges();

 


请各位大神指点一下。   纠结了好半天了。

第一次更新数据没有问题。  但是第二次更新数据的时候就会出现上述错误。  

刘剑_1989的主页 刘剑_1989 | 初学一级 | 园豆:4
提问于:2015-02-12 15:04
< >
分享
最佳答案
1

查询过这个实体,你再这样放一个new的实体进去跟踪.他会有2个相同ID的对象,然后就报异常了

收获园豆:70
吴瑞祥 | 高人七级 |园豆:29364 | 2015-02-12 15:18

恩恩。    原因肯定是这样的。  只是不知道该怎么操作让之前的查询失效。。。   如果context.Dispose()的话  就不能在用了。 

刘剑_1989 | 园豆:4 (初学一级) | 2015-02-12 15:28

@刘剑_1989: 你干嘛要让原来的查询失效?

你既然用ef了.那除了插入数据,其它时候就不要new对象了.

要操作前线从上下文里把实体查询出来.再修改再保存,就不会有这些乱七八糟的问题了

吴瑞祥 | 园豆:29364 (高人七级) | 2015-02-12 15:36

@吴瑞祥: 结局问题办法。  查询单条数据的时候不从redis中查询  用EF查询。。。。。。。。。。。。。

 

感觉解决这个问题的办法真心好奇葩。。。 

刘剑_1989 | 园豆:4 (初学一级) | 2015-02-12 16:44

@刘剑_1989: 真的一点都不奇葩...你这是不理解实体追踪的意义..

你这种单条数据就算从ef里查,也只是查询的缓存,而不是数据库

吴瑞祥 | 园豆:29364 (高人七级) | 2015-02-12 17:34
其他回答(5)
0

context.Entry<Penson>(item).State = EntityState.Modified;  

如果你非要用这种方式来更新,那我就不说了。

Launcher | 园豆:45045 (高人七级) | 2015-02-12 15:09

恕小弟才疏学浅  我这修改方法需要使用泛型。  有泛型还有其他的修改方式么?

支持(0) 反对(0) 刘剑_1989 | 园豆:4 (初学一级) | 2015-02-12 15:25

@刘剑_1989: 更新是这样的,

T existing = Context.Set<T>().Find

如果 existing == null, Context.Set<T>().Add(item);

否则, 将 item 的值赋给 existing(不包括主键的值),

最后,Context.SaveChanges

支持(1) 反对(1) Launcher | 园豆:45045 (高人七级) | 2015-02-12 16:07

@Launcher: 正解,修改更新数据到数据库有两种方式:连接模式下和断开模式下,楼主出问题的原因在因为连接模式,同一个上下文要缓存了两个同一个主键的对象,EF的上下文不允许这种情况出现。按照@Launcher 的提示,可以更新成功。代码如下

public bool UpdateEntity(UserInfo userInfo)
{
UserInfo user = context.Set<UserInfo>().Find(userInfo.UserId);

if(user!=null)
{
user.UserName = userInfo.UserName;
user.Password = userInfo.Password;
user.Email = userInfo.Email;
user.Phone = userInfo.Phone;
user.Remark = userInfo.UserName;
}

return context.SaveChanges() > 0;
}

支持(0) 反对(0) 追忆似水流年 | 园豆:160 (初学一级) | 2016-07-19 08:54

@追忆似水流年: 微软的那种更新数据库的方式是在同一个上下文更新数据,更新完上下文就不在使用,会被回收,楼主出问题的原因在于是系统中上下文一直在使用(静态类创建的),一直是连接模式,这时会实体状态跟踪,所以可以使用Context.Set<T>().Find方法,得到对象实体,摆脱实体状态跟踪,来更新数据

支持(0) 反对(0) 追忆似水流年 | 园豆:160 (初学一级) | 2016-07-19 08:58

@追忆似水流年: 这个Find方法会从上下文缓存通过主键寻找数据,找不到再去数据库中寻找,如果找到了,数据就会返回,这个返回的数据就不会缓存在上下文中,可以修改后提交到数据库中。如果上下文缓存和数据库中都找不到,就会返回null.

支持(0) 反对(0) 追忆似水流年 | 园豆:160 (初学一级) | 2016-07-19 09:03
0

你这是被微软坑了。微软网站都是这么写的,可是你别这么用啊。

收获园豆:30
爱编程的大叔 | 园豆:30773 (高人七级) | 2015-02-12 15:17

在使用泛型的情况下 还有其他的修改方式么? 请指点一下吧,   感激不尽。  

支持(0) 反对(0) 刘剑_1989 | 园豆:4 (初学一级) | 2015-02-12 15:26

@刘剑_1989: 你代码不全啊,谁知道你干啥了。

你代码全的话,估计楼上楼下这两位都能有办法,我就凑凑热闹,哈哈。

写错的我是知道,至于怎么才能写对,那....

支持(0) 反对(0) 爱编程的大叔 | 园豆:30773 (高人七级) | 2015-02-12 15:31

@爱编程的大叔: 

 

我是用的redis做了一层缓存。  第一次是 从缓存读取数据,修改字段。   提交保存EF,  成功后修改redis。  但是第二次 在从缓存读取数据 修改单独字段,  在提交保存EF的时候就报错了。 

支持(0) 反对(0) 刘剑_1989 | 园豆:4 (初学一级) | 2015-02-12 15:34

@刘剑_1989: 看了你回答楼下的,

你的context是永远不失效的?如果context不失效,你又何必用redis读?

context里面不是已经有一个了?

支持(0) 反对(0) 爱编程的大叔 | 园豆:30773 (高人七级) | 2015-02-12 15:54

@爱编程的大叔: 

补充问一个小白的问题。   EF是不是查询过一次数据之后 自动的把这些数据进行缓存处理了?  第二次查询的时候直接从缓存中读取? 

支持(0) 反对(0) 刘剑_1989 | 园豆:4 (初学一级) | 2015-02-12 16:00

@刘剑_1989: 你想想看咯,你看看你在Attach的时候出错,有没有产生数据库查询,这个你总应该懂得看吧?

支持(0) 反对(0) 爱编程的大叔 | 园豆:30773 (高人七级) | 2015-02-12 16:03

@爱编程的大叔: 那我可不可以说  其实用EF+redis的结合本身就是错误的呢。 

支持(0) 反对(0) 刘剑_1989 | 园豆:4 (初学一级) | 2015-02-12 16:05

@刘剑_1989: 那我就不知道了,你EF明显不熟悉的样子,不知道你搞什么大项目,

居然连REDIS都出来了。这得有几千万的大项目啊。

 

REDIS+EF是没有错,问题看你怎么用。

 

你可别听人说EF性能差这事,

说这事的人99%是没有脑子的,还有1%的人是只干1个亿以上生意的人。

支持(0) 反对(0) 爱编程的大叔 | 园豆:30773 (高人七级) | 2015-02-12 16:07

@爱编程的大叔: EF效率我不做评论。  说道熟与不熟  可能也仅仅是处于在 会用,但是不懂得怎么用效率更高。 因为最近一直自己在搞这些东西。  redis+EF的结合使用。  对这两样东西都不是很熟, 所以总是遇到各种奇葩的问题。   

支持(0) 反对(0) 刘剑_1989 | 园豆:4 (初学一级) | 2015-02-12 16:16

@刘剑_1989: 那我的建议是你尽可能先熟悉其中一种,比如EF。

支持(0) 反对(0) 爱编程的大叔 | 园豆:30773 (高人七级) | 2015-02-12 16:33
0

public bool Update<T>(T entity) where T : class
{

Context.Set<T>().Attach(entity);
Context.Entry(entity).State = EntityState.Modified;
return Context.SaveChanges() > 0;

}

[人在江湖] | 园豆:258 (菜鸟二级) | 2015-02-12 15:42

在 Context.Set<T>().Attach(entity);  的时候就直接报错了。 

支持(0) 反对(0) 刘剑_1989 | 园豆:4 (初学一级) | 2015-02-12 15:50

@刘剑_1989: 你的person表设置了主键没,是不是自动增长的

支持(0) 反对(0) [人在江湖] | 园豆:258 (菜鸟二级) | 2015-02-12 15:55

@人在江湖博客: 设置了主键 自增。 

支持(0) 反对(0) 刘剑_1989 | 园豆:4 (初学一级) | 2015-02-12 15:55
0

最简单的方法,你已经查了,那么用你查出来的实体来存储更新后的数据,这样id一致而且还省下资源

毒逆天 | 园豆:261 (菜鸟二级) | 2015-11-13 11:01
0

Context.Entry(entity).State = EntityState.Modified

这一步相当于将entity注册为修改状态,如果没有提前attach的话会自动attach。当第一次Context.SaveChanges()的时候,会将entity这条数据保存到缓存中,所以你下次如果想修改这条数据的话,需要保证两个条件:

1.第二次的entity一定是被跟踪的实体类,也就是说如果你用了AsNoTracking得到的entity,那么entity是一个新的实体类,没有被跟踪,那么无论你如何想要将其注册为Modified,都是无效的,因为它与缓存中的entity冲突。

2.不要用Attach。因为1中已经保证了是一个被跟踪的实体类,已经在缓存中,不需要再Attach。

 

因此,总结起来就是:

查询的时候不要用AsNoTracking

修改的时候不要用Attach

阿木亮 | 园豆:202 (菜鸟二级) | 2017-05-19 22:08
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册