Repository模式中,Update总是失败及其解析
在Repository模式中,我的Update方法总是无法更新实体,这个非常郁闷,Update方法如下:
1: public virtual void Update(T entity)
2: {
3: try
4: {
5: if (entity == null) throw new ArgumentNullException("实体类为空");
6: Context.Entry(entity).State = EntityState.Modified;
7: //Context.SaveChanges();
8: }
9: catch (DbEntityValidationException dbex)
10: {
11: var msg = string.Empty;
12: foreach (var validationErrors in dbex.EntityValidationErrors)
13: foreach (var validateionError in validationErrors.ValidationErrors)
14: msg += string.Format("Property:{0} Error:{1}", validateionError.PropertyName, validateionError.ErrorMessage);
15:
16: var fail = new Exception(msg, dbex);
17: throw fail;
18: }
19: }
看上去是没有任何问题的代码,一旦有实体更新的时候,总会出现如下的错误提示:
看字面意思,好像是我的EntityState设置不正确导致的,虽然我尝试过重新设置几次EntityState,但是仍旧无法解决我的问题。
然后实在找不出原因,就利用关键字 “ EF Repository Update ”在Google上面搜集,果然找到一篇文章:Advanced Entity Framework 6 Scenarios for an MVC 5 Web Application (12 of 12),其中有一段话,提出了问题的所在:
This happened because of the following sequence of events:
The Edit method calls the ValidateOneAdministratorAssignmentPerInstructor method, which retrieves all departments that have Kim Abercrombie as their administrator. That causes the English department to be read. As a result of this read operation, the English department entity that was read from the database is now being tracked by the database context.
The Edit method tries to set the Modified flag on the English department entity created by the MVC model binder, which implicitly causes the context to try to attach that entity. But the context can't attach the entry created by the model binder because the context is already tracking an entity for the English department.
One solution to this problem is to keep the context from tracking in-memory department entities retrieved by the validation query. There's no disadvantage to doing this, because you won't be updating this entity or reading it again in a way that would benefit from it being cached in memory.
问题的原因如下:
在Context对象中,已经hold住了一个需要操作的对象,当我们把EntityState修改成modified的时候,Context会再次去加载那个操作对象,但是这样加载是无法成功的,因为当前已经存在一个对象了,再加载会导致重复,然后抛出失败的错误。
解决方法很简单,就是在展示列表的时候,利用AsNoTracking将Hold住的对象释放掉即可。我们修改代码如下:
1: public virtual T Get(Expression<Func<T, bool>> where)
2: {
3: return Dbset.Where(where).AsNoTracking().FirstOrDefault<T>();
4: }
5:
6: public virtual IQueryable<T> GetMany(Expression<Func<T, bool>> where)
7: {
8: return Dbset.Where(where).AsNoTracking();
9: }
然后提交,OK,问题解决。
=============================Update 2014.09.19======================
看到评论中有朋友虽然按照上述方法,但是仍然无法解决这一问题。原因是在Context中还保留有当前实体的副本所致,这里只要我们将实体副本从内存中完全移除,就可以了。
//用于监测Context中的Entity是否存在,如果存在,将其Detach,防止出现问题。
private Boolean RemoveHoldingEntityInContext(T entity)
{
var objContext = ((IObjectContextAdapter)_context).ObjectContext;
var objSet = objContext.CreateObjectSet<T>();
var entityKey = objContext.CreateEntityKey(objSet.EntitySet.Name, entity); Object foundEntity;
var exists = objContext.TryGetObjectByKey(entityKey, out foundEntity); if (exists)
{
objContext.Detach(foundEntity);
} return (exists);
}
然后在Repository中,在进行更新和删除之前,运行一下即可:
public T Remove(T entity)
{
try
{
RemoveHoldingEntityInContext(entity); _context.DbSet<T>().Attach(entity);
return _context.DbSet<T>().Remove(entity);
}
catch (DbEntityValidationException dbex)
{
var msg = string.Empty;
foreach (var validationErrors in dbex.EntityValidationErrors)
foreach (var validateionError in validationErrors.ValidationErrors)
msg += string.Format("属性:{0} 错误:{1}", validateionError.PropertyName, validateionError.ErrorMessage);
var fail = new Exception(msg, dbex);
throw fail;
}
} public T Update(T entity)
{
try
{
RemoveHoldingEntityInContext(entity); var updated = _context.DbSet<T>().Attach(entity);
_context.DbContext.Entry(entity).State = EntityState.Modified;
return updated;
}
catch (DbEntityValidationException dbex)
{
var msg = string.Empty;
foreach (var validationErrors in dbex.EntityValidationErrors)
foreach (var validateionError in validationErrors.ValidationErrors)
msg += string.Format("属性:{0} 错误:{1}", validateionError.PropertyName, validateionError.ErrorMessage);
var fail = new Exception(msg, dbex);
throw fail;
}
}
Repository模式中,Update总是失败及其解析的更多相关文章
- Repository模式中,Update总是失败及其解析(转)
出处:http://www.cnblogs.com/scy251147/p/3688844.html 关于Entity Framework中的Attached报错的完美解决方案终极版 前发表过一篇文章 ...
- 使用Repository模式构建数据库访问层
使用Repository模式构建数据库访问层 使用ASP.NET Web Api构建基于REST风格的服务实战系列教程[二]——使用Repository模式构建数据库访问层 系列导航地址http:// ...
- 使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【二】——使用Repository模式构建数据库访问层
系列导航地址http://www.cnblogs.com/fzrain/p/3490137.html 前言 在数据访问层应用Repository模式来隔离对领域对象的细节操作是很有意义的.它位于映射层 ...
- Entity Framework Repository模式
Repository模式之前 如果我们用最原始的EF进行设计对每个实体类的“C(增加).R(读取).U(修改).D(删除)”这四个操作. 第一个:先来看看查询,对于实体类简单的查询操作,每次都是这样的 ...
- (转)MVC中的Repository模式
1.首先创建一个空的MVC3应用程序,命名为MyRepository.Web,解决方案命名为MyRepository. 2.添加一个类库项目,命名为MyRepository.DAL,添加一个文件夹命名 ...
- MVC中的Repository模式
1.首先创建一个空的MVC3应用程序,命名为MyRepository.Web,解决方案命名为MyRepository. 2.添加一个类库项目,命名为MyRepository.DAL,添加一个文件夹命名 ...
- 在 Laravel 5 中使用 Repository 模式实现业务逻辑和数据访问的分离
1.概述 首先需要声明的是设计模式和使用的框架以及语言是无关的,关键是要理解设计模式背后的原则,这样才能不管你用的是什么技术,都能够在实践中实现相应的设计模式. 按照最初提出者的介绍,Reposito ...
- 项目开发中的一些注意事项以及技巧总结 基于Repository模式设计项目架构—你可以参考的项目架构设计 Asp.Net Core中使用RSA加密 EF Core中的多对多映射如何实现? asp.net core下的如何给网站做安全设置 获取服务端https证书 Js异常捕获
项目开发中的一些注意事项以及技巧总结 1.jquery采用ajax向后端请求时,MVC框架并不能返回View的数据,也就是一般我们使用View().PartialView()等,只能返回json以 ...
- MVC架构中的Repository模式 个人理解
关于MVC架构中的Repository模式 个人理解:Repository是一个独立的层,介于领域层与数据映射层(数据访问层)之间.它的存在让领域层感觉不到数据访问层的存在,它提供一个类似集合的接 ...
随机推荐
- HTML5手机APP开发入门(1)
HTML5手机APP开发入门(1) 开发框架 Ionicframework V2 + Angular 2 具体内容可以参考一下网站 http://ionicframework.net/ http:// ...
- AutoCAD2007专业版
07版的AutoCAD应该是一个很经典的版本了,点此下载,附带破解注册机和天正的插件包,可以查看天正软件画的图纸. AutoCAD2007本身没有标签工具,切换窗口很不方便,如果能配合多标签插件Doc ...
- centos 开启启动服务优化
默认开机启动服务列表:(此表转自 http://www.ha97.com/4815.html,另有多处补充) 服务名称 功能 默认 建议 备注说明 NetworkManager 用于自动连接网 ...
- Ubuntu虚拟机JeOS安装-2016.08.28
根据官网的说明JeOS的镜像已经在官方不发行了,所以你在别的帖子里看到的安装jeos的镜像地址已经不适用了. 那么应该如何安装这种最小版本的linux操作系统呢? 其一,如果想要安装老版本的jeos系 ...
- 成功在神舟K650c-i7 d2(i7-4700MQ、HM87)上装好了Windows XP
成功在神舟K650c-i7 d2(i7-4700MQ.HM87)上装好了Windows XP 本来已经在K650c上装好了Windows7.Windows8双系统,奈何某些旧软件只能在Windows ...
- TNSNAMES.ORA 配置
上面的sqlnet.ora文件说明:SQLNET.AUTHENTICATION_SERVICES= (NTS)——这个表示采用os认证,在数据库服务器上,可以利用sqlplus “/ as sysdb ...
- "无法启动应用程序,工作组信息文件丢失,或是已被其他用户已独占方式打开"解决办法
当程序用ado的jet4.0方式连接mdb数据库的时候,对于设有access数据库密码的mdb的访问居然报错“无法启动应用程序,工作组信息文件丢失,或是已被其他用户已独占方式打开”. ADOConne ...
- [转] Linux学习之CentOS(三十六)--FTP服务原理及vsfptd的安装、配置
本篇随笔将讲解FTP服务的原理以及vsfptd这个最常用的FTP服务程序的安装与配置... 一.FTP服务原理 FTP(File Transfer Protocol)是一个非常古老并且应用十分广泛的文 ...
- ECSHOP安装百度编辑UEditor教程
ECSHOP系统自带的编辑器大家用过都知道,难用不说,还不能批量上传图片.很多朋友都喜欢百度编辑器,因为百度编辑器功能强大,使用方便,而且不会生成太多多余代码.网上有许多ECSHOP整合百度编辑器的教 ...
- Xcode7.x中安装Alcatraz
将Xcode升级了,发现Alcatraz失效了: xcode7.x安装插件命令:curl -fsSL https://raw.github.com/supermarin/Alcatraz/master ...