如果我们在先前的步骤中读取过数据,如

var list = db.Model.ToList();

之后再,附加

var o = new Model { Id = 1 };
db.Model.Attach(o);

就会报,类似这样的错误

Attaching an entity of type 'efAutoDetach.Model' failed because another entity of the same type already has the same primary key value. This can happen when using the 'Attach' method or setting the state of an entity to 'Unchanged' or 'Modified' if any entities in the graph have conflicting key values. This may be because some entities are new and have not yet received database-generated key values. In this case use the 'Add' method or the 'Added' entity state to track the graph and then set the state of non-new entities to 'Unchanged' or 'Modified' as appropriate.

意思是说,在上下文中,已经有一个同样主键的东西了。

这样的错误通常在直接更新时遇到,不是先查出来再更新,而是直接new一个出来,附加上去更新

 

第一次查询后,本地的local中就已经有相应的实体了。如果我们把local中的实体detach了,那我们新new的对象就可以attch上去了。

 

 

Detach的扩展方法

 

public static void Detach<T>(this DbContext db, T obj) where T : class
{
ObjectContext oc = ((IObjectContextAdapter)db).ObjectContext;
oc.Detach(obj);
}

获取主键信息的扩展方法

public static IEnumerable<string> GetEntityKeys<T>(this DbContext db) where T : class
{
ObjectContext oc = ((IObjectContextAdapter)db).ObjectContext;
var keys = oc.CreateObjectSet<T>().EntitySet.ElementType.KeyProperties.Select(x => x.Name);
return keys;
}

我们需要通过主键信息构建一个表达式树,用于从local中获取实体

private static Expression<Func<T, bool>> GetFindExp<T>(T obj, IEnumerable<string> keys) where T : class
{
var p = Expression.Parameter(typeof(T), "x"); var keyexps = keys.Select(x =>
{
var member = Expression.PropertyOrField(p, x);
var objV = typeof(T).GetProperty(x).GetValue(obj);
var eq = Expression.Equal(member, Expression.Constant(objV));
return eq;
}).ToList(); if (keys.Count() == 1)
{
return Expression.Lambda<Func<T, bool>>(keyexps[0], new[] { p });
} var and = Expression.AndAlso(keyexps[0], keyexps[1]);
for (var i = 2; i < keyexps.Count; i++)
{
and = Expression.AndAlso(and, keyexps[i]);
}
return Expression.Lambda<Func<T, bool>>(and, new[] { p });
}
于是可以找到local中的
public static T FindLocal<T>(this DbContext db, T obj) where T : class
{
var keys = db.GetEntityKeys<T>();
var func = GetFindExp<T>(obj, keys).Compile();
return db.Set<T>().Local.FirstOrDefault(func);
}

最后综合使用上面的几个方法

public static void DetachOther<T>(this DbContext db, T obj) where T : class
{
var local = db.FindLocal(obj);
if (local != null)
{
db.Detach(local);
}
}

使用

var o = new Model { Id = 1 };
db.DetachOther(o);
db.Model.Attach(o);
在attach之前,先detachother

以上。

EF Attach时已存在的处理方式的更多相关文章

  1. C# EF Attach 与 Entry

    先了解一下 EF 框架的 EntityState 在使用EF框架时, 我们通常都是通过调用 SaveChanges() 方法把增加/修改/删除的数据提交到数据库,但是上下文是如何知道实体对象是增加.修 ...

  2. webapi 控制器接收POST参数时必须以对象的方式接收

    webapi    控制器接收POST参数时必须以对象的方式接收

  3. 未能找到任何适合于指定的区域性或非特定区域性的资源。请确保在编译时已将“xxx.Resources.resources”正确嵌入或链接到程序集

    今天在测试一个工程的时候,突然遇到了这样一个问题: 错误信息:System.Resources.MissingManifestResourceException: 未能找到任何适合于指定的区域或非特定 ...

  4. 请确保在编译时已将“AjaxControlToolkit.Properties.Resources.NET4.resources”正确嵌入或链接到程序集“AjaxControlToolkit”

    原文:请确保在编译时已将"AjaxControlToolkit.Properties.Resources.NET4.resources"正确嵌入或链接到程序集"AjaxC ...

  5. EF的三种数据加载方式

    EF的关联实体加载有三种方式:Lazy Loading,Eager Loading,Explicit Loading,其中Lazy Loading和Explicit Loading都是延迟加载. (一 ...

  6. linux文件名乱码时删除或改名的方式(转载)

    转自:http://www.linuxsa.cn/when-linux-file-name-topsy-turvy-deleted-or-renamed.html linux文件名乱码时删除或改名的方 ...

  7. SQLPlus在连接时通常有四种方式

    SQLPlus在连接时通常有四种方式 1. ? 1 sqlplus / as sysdba 操作系统认证,不需要数据库服务器启动listener,也不需要数据库服务器处于可用状态.比如我们想要启动数据 ...

  8. 第十节: EF的三种追踪实体状态变化方式(DBEntityEntry、ChangeTracker、Local)

    一. 简介 我们在前面章节介绍EF基本增删改的时候,曾说过EF的SaveChanges()方法,会一次性的将所有的实体的状态变化统一提交到数据库,那么你是否想过EF的实体会有哪些状态变化呢?什么原因会 ...

  9. MVC3+EF4.1学习系列(五)----- EF查找导航属性的几种方式

    文章索引和简介 通过上一篇的学习 我们把demo的各种关系终于搭建里起来 以及处理好了如何映射到数据库等问题 但是 只是搭建好了关系 问题还远没有解决 这篇就来写如何查找导航属性 和查找导航属性的几种 ...

随机推荐

  1. hdu1875 畅通工程再续 最小生成树并查集解决---kruskal

    http://acm.hdu.edu.cn/showproblem.php?pid=1875 New~ 欢迎“热爱编程”的高考少年——报考杭州电子科技大学计算机学院关于2015年杭电ACM暑期集训队的 ...

  2. Linux内核--异常和中断的区别

          相信大家都知道非常著名的两个名词:异常和中断,不过,你真的理解这两个名词在说什么吗?它们之间有什么区别呢?       1.中断       大家都知道,当我们在敲击键盘的同时就会产生中断 ...

  3. .svn批量删除

    c.bat @echo on @rem 删除SVN版本控制目录 @rem for /r . %%a in (.) do @if exist "%%a\.svn" @echo &qu ...

  4. BigDecimal除法运算出现java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result的解决办法

    BigDecimal除法运算出现java.lang.ArithmeticException: Non-terminating decimal expansion; no exact represent ...

  5. Less/Sass编译工具,koala使用指南

    如果你正在使用sass.less或coffee,而没有注意到koala, 那说明你可能已经好久没有更新你的知识库了.koala这个由国人编写的,用于编译sass.less.coffee利器,在最近的短 ...

  6. ubuntu bless 16字节每行

    打开Preferences配置 输入路径:/usr/share/bless/bless-16-bytes-per-row.layout 或者使用以下配置 cat /home/scue/.config/ ...

  7. 2014 Hangjs 见闻流水账第一天

    前言 6月21日~6月22日, 第一次跑远门去参加一个大会(广州 -> 杭州),本来打算,在火车的回来的路上,把这两天的东西记录一下,不过,火车上的环境实在恶劣,同时也高估了自己的专注力,所以, ...

  8. ELK——Logstash 2.2 mutate 插件【翻译+实践】

    官网地址 本文内容 语法 测试数据 可选配置项 mutate 插件可以在字段上执行变换,包括重命名.删除.替换和修改.这个插件相当常用. 比如: 你已经根据 Grok 表达式将 Tomcat 日志的内 ...

  9. Dell U2913WM使用感受

    21:9比例,本来想代替双屏的,一周用下来还是不适应,如何能弯成曲面就爽了.感觉最舒服的还是以前19寸5:4双屏,点距大. 还尝试在旁边立个23寸,看了15分钟就受不了,头晕. 漏光,还行. 加了个A ...

  10. Swift 关键字汇总

    常见的关键字有以下4种 与声明有关的关键字:class.deinit.enum.extension.func.import.init.let.protocol.static.struct.subscr ...