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

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. SAP大数据为"海上F1"提供技术支持

    “海上F1”的2014极限帆船赛在青岛开赛,这场大赛是技术与体育高度融合的盛会.比赛中,每一个船员将使用各种高新技术,应尽所能,战胜对手.很多人之所以喜欢这样的比赛,是因为帆船比赛是世界上最复杂的一项 ...

  2. jQuery选择器和选取方法

        我们已经使用了带有简单Css选择器的jQuery选取函数:$().现在是时候深入了解jQuery选择器语法,以及一些提取和扩充选中元素集的方法了. 一.jQuery选择器 在CSS3选择器标淮 ...

  3. (转)c#.net常用字符串函数

    Compare 比较字符串的内容,考虑文化背景(场所),确定某些字符是否相等 CompareOrdinal 与Compare一样,但不考虑文化背景 Format 格式化包含各种值的字符串和如何格式化每 ...

  4. Andriod Studio 开发环境安装和配置

    Android Studio安装配置详细步骤(图文):http://www.2cto.com/kf/201604/500642.html第一次使用Android Studio时你应该知道的一切配置 : ...

  5. Windows 7 中设置VPN(PPTP连接方式)

    第一步:打开控制面板-网络和共享中心(如图) 第二步:点击-设置新的连接或网络(如图) 第三步:选择-连接到工作区-下一步(如图) 第四步:如果已经存在其他连接,则在这一步选择”否,创建新连接“:如果 ...

  6. WPF 的datagrid 列名中没有显示下划线是怎么回事?

    引用:http://www.cnblogs.com/sqzhuyi/archive/2011/07/26/sqlserverclient.html#2831497 功能介绍:输入查询语句,显示列表 出 ...

  7. Web service standards: SOAP, REST, OData, and more

    Web service standards: SOAP, REST, OData, and more So far, we've covered the components of a web ser ...

  8. zendStudio 10.5破解

    1.下载zendStudio 10.5(mac系统)     windows系统安装文件 并安装. 2.下载破解文件,并覆盖安装目录plugins同名文件,要注意版本. 3.启动程序,输入注册码: 3 ...

  9. 延长Toast显示时间

    ---恢复内容开始--- 由于Toast的显示时间只有两种: Toast.LENGTH_SHORT: 2秒 Toast.LENGTH_LONG: 3.5秒 而且是写死的,没给开发者自定义时间的权利,所 ...

  10. 三层架构与MVC &amp; 设计模式的较量

    刚刚学习了三层架构,并且正在实际应用中,但随着学习的深入,又了解到了一个叫MVC的东西,(早在设计模式中就听到过MVC,仅仅是简单查了一下什么意思.)如今正好把这三个东西放在一起聊聊. 三层 是一个分 ...