EF Attach时已存在的处理方式
如果我们在先前的步骤中读取过数据,如
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时已存在的处理方式的更多相关文章
- C# EF Attach 与 Entry
先了解一下 EF 框架的 EntityState 在使用EF框架时, 我们通常都是通过调用 SaveChanges() 方法把增加/修改/删除的数据提交到数据库,但是上下文是如何知道实体对象是增加.修 ...
- webapi 控制器接收POST参数时必须以对象的方式接收
webapi 控制器接收POST参数时必须以对象的方式接收
- 未能找到任何适合于指定的区域性或非特定区域性的资源。请确保在编译时已将“xxx.Resources.resources”正确嵌入或链接到程序集
今天在测试一个工程的时候,突然遇到了这样一个问题: 错误信息:System.Resources.MissingManifestResourceException: 未能找到任何适合于指定的区域或非特定 ...
- 请确保在编译时已将“AjaxControlToolkit.Properties.Resources.NET4.resources”正确嵌入或链接到程序集“AjaxControlToolkit”
原文:请确保在编译时已将"AjaxControlToolkit.Properties.Resources.NET4.resources"正确嵌入或链接到程序集"AjaxC ...
- EF的三种数据加载方式
EF的关联实体加载有三种方式:Lazy Loading,Eager Loading,Explicit Loading,其中Lazy Loading和Explicit Loading都是延迟加载. (一 ...
- linux文件名乱码时删除或改名的方式(转载)
转自:http://www.linuxsa.cn/when-linux-file-name-topsy-turvy-deleted-or-renamed.html linux文件名乱码时删除或改名的方 ...
- SQLPlus在连接时通常有四种方式
SQLPlus在连接时通常有四种方式 1. ? 1 sqlplus / as sysdba 操作系统认证,不需要数据库服务器启动listener,也不需要数据库服务器处于可用状态.比如我们想要启动数据 ...
- 第十节: EF的三种追踪实体状态变化方式(DBEntityEntry、ChangeTracker、Local)
一. 简介 我们在前面章节介绍EF基本增删改的时候,曾说过EF的SaveChanges()方法,会一次性的将所有的实体的状态变化统一提交到数据库,那么你是否想过EF的实体会有哪些状态变化呢?什么原因会 ...
- MVC3+EF4.1学习系列(五)----- EF查找导航属性的几种方式
文章索引和简介 通过上一篇的学习 我们把demo的各种关系终于搭建里起来 以及处理好了如何映射到数据库等问题 但是 只是搭建好了关系 问题还远没有解决 这篇就来写如何查找导航属性 和查找导航属性的几种 ...
随机推荐
- AngularJS(一)
什么是AngularJS[双向数据绑定:从界面的操作能实时反映到数据,数据的变更能实时展现到界面.]?1.AngularJS 使得开发现代的单一页面应用程序(SPAs:Single Page Appl ...
- iOS开发Swift篇(01) 变量&常量&元组
iOS开发Swift篇(01) 变量&常量&元组 说明: 1)终于要写一写swift了.其实早在14年就已经写了swift的部分博客,无奈时过境迁,此时早已不同往昔了.另外,对于14年 ...
- VS2015安装 Secondary Installer Setup Failed求解决方案
个人同步本文博客地址http://aehyok.com/Blog/Detail/64.html 个人网站地址:aehyok.com QQ 技术群号:206058845,验证码为:aehyok 本文文章 ...
- java获取点击微信自定义菜单的用户openid
测试: 先上 请求类 HttpRequesto package reyo.sdk.utils.weixin; import java.io.BufferedReader; import java.io ...
- The web application [] appears to have started a thread named [Abandoned connection cleanup thread] com.mysql.jdbc.AbandonedConnectionCleanupThread
01-Jul-2016 14:25:30.937 WARNING [localhost-startStop-1] org.apache.catalina.loader.WebappClassLoade ...
- mysql查看被锁住的表,正在进行的进程,已经杀掉进程的方法
mysql查看被锁的进程 //查看所有进程show processlist; //查询是否锁表show OPEN TABLES where In_use > 0; //查看被锁住的 SELECT ...
- NFS性能优化
参考: http://www.techrepublic.com/blog/linux-and-open-source/tuning-nfs-for-better-performance/ 1.服务器端 ...
- WPF 触发器
属性触发器:数据触发器:事件触发器
- JAVA利用enum结合testng做数据驱动示例
数据驱动是做自动化测试中很重要的一部分,数据源的方案也是百花八门了,比如利用外部文件,直接在@DataProvider中写死等等,我们今天介绍一下利用enum来做数据源,先来看一下enum的写法: p ...
- Linux下配置ip地址四种方法
linux系统安装完,以后通过命令模式配置网卡IP.配置文件通常是/etc/sysconfig/network-scripts/ifcfg-interface-nameifconfig后显示的内容,l ...