我们经常会遇到这样的问题:Update一个entity的部分数据时,通常需要new一个新的对象,然后事这新的对象Attach到Context中,代码如下所示:

         /// <summary>
/// 只更新storedAddress数据中的DefaultAddress字段,更新为false
/// 将默认地址改为不是默认地址
/// </summary>
/// <param name="storedAddress">地址信息</param>
public void Update(StoredAddress storedAddress)
{
StoredAddress s = new StoredAddress { StoredAddressID = storedAddress.StoredAddressID };
s.DefaultAddress = true; _context.StoredAddresses.Attach(s); s.DefaultAddress = false; _context.SaveChanges();
_context.Detach(s);
}

_context.StoredAddresses.Attach(s);程序在这一句时往往会报出异常---Context 中已经存在有相同键的对象了,从而使得我们的部分更新不能成功。

经过分析,我们知道Context 中存在了一个对象,这个对象和我们new的对象s有相同的键,那么这个对象哪一个对象呢?通过代码我们不难看出这个对象是storedAddress,所以我们需要将storedAddress对象从Context 中Detach。我们的新代码如下:

          /// <summary>
/// 只更新storedAddress数据中的DefaultAddress字段,更新为false
/// 将默认地址改为不是默认地址
/// </summary>
/// <param name="storedAddress">地址信息</param>
public void UpdateStoredAddressDefaultAddress(StoredAddress storedAddress)
{
//先撤销跟踪
_context.Detach(storedAddress); StoredAddress s = new StoredAddress { StoredAddressID = storedAddress.StoredAddressID };
s.DefaultAddress = true; _context.StoredAddresses.Attach(s); s.DefaultAddress = false; _context.SaveChanges();
_context.Detach(s);
}

通常我们并不知道对象有没有Attach,下面提供一个方法来确定对象有没有Attach:

  public static bool IsAttached(this AllureContext context, object entity)
{
if (entity == null)
{
throw new ArgumentNullException("entity");
}
ObjectStateEntry entry;
if (context.ObjectStateManager.TryGetObjectStateEntry(entity, out entry))
{
return (entry.State != System.Data.EntityState.Detached);
}
return false;
}

上面的方法调用为_context.IsAttached(storedAddress),这要求我们必须知道一个对象,然后才能判断这个对象有没有被Attached。这是比较普遍的解决办法,因为我们的storedAddress对象已经确定。如果我们将第一段代码改为:

         /// 只更新storedAddress数据中的DefaultAddress字段,更新为false
/// 将默认地址改为不是默认地址
/// </summary>
/// <param name="id">需要修改的对象的id</param>
public void Update(int id)
{ StoredAddress s = new StoredAddress { StoredAddressID = id };
s.DefaultAddress = true; _context.StoredAddresses.Attach(s); s.DefaultAddress = false; _context.SaveChanges();
_context.Detach(s);
}

此时我们不知道有没有和s对象具有相同键的对象存在于Context,就算我们现在知道有个对象存在Context中,并且和s对象就有相同的键,但是我们不知到这个对象是什么,想要Detach这个对象,比较难了,因为只有一个id,我在网上找了一些办法:

  1. 办法一,直接写成Sql 语句,从而更新数据库中的对象
  2. 办法二,通过id从数据库中得到这个对象,然后Deatch这个对象

对于办法一,因为我们用的是EF,所以我们还想用EF的东西;对于办法二,我们需要在写一个方法,这个方法负责从数据库来得到这个对象,有点麻烦,性能方面,没有测试过,只是感觉麻烦。那么EF有么有给我们提供一些方法让我们通过仅有的信息得到这个对象呢,答案是有。方法如下

            object originalItem = null;
            System.Data.EntityKey key = _context.CreateEntityKey("StoredAddresses", s);
            if (_context.TryGetObjectByKey(key, out originalItem))    
            {
                _context.Detach(originalItem);         
            }
注意:System.Data.EntityKey key = _context.CreateEntityKey("StoredAddresses", s);是EF5.0中的写法
EF6.0中的写法为System.Data.Entity.Core.EntityKey key = _context.CreateEntityKey("StoredAddresses", s);
这个方法放到这里有些难理解,我们可以将它放到我们的代码中:
         /// 只更新storedAddress数据中的DefaultAddress字段,更新为false
/// 将默认地址改为不是默认地址
/// </summary>
/// <param name="id">需要修改的对象的id</param>
public void Update(int id)
{ StoredAddress s = new StoredAddress { StoredAddressID = id }; 10 object originalItem = null;
11 System.Data.EntityKey key = _context.CreateEntityKey("StoredAddresses", s);
if (_context.TryGetObjectByKey(key, out originalItem))
{
_context.Detach(originalItem);
} s.DefaultAddress = true; _context.StoredAddresses.Attach(s); s.DefaultAddress = false; _context.SaveChanges();
_context.Detach(s);
}

我们通过EntityKey来获得这个对象,然后Detach这个对象,随后再Attach我们new的对象s,就可以修改数据库了。此方法中要注意CreateEntityKey()的用法,第一个参数entitySetName,注意名称要和 Navigation Properties的名称一样,具体详见http://msdn.microsoft.com/en-us/library/system.data.objects.objectcontext.createentitykey.aspx

好了,我们的修改已经完成。

补充一下,我们的DBcontext实现为:

public partial class Context : ObjectContext

{

//具体实现

}

而不是DbContext。

这是两者最根本的区别:ObjectContext是一种模型优先的开发模式,DbContext是代码优先的开发模式。

所以有些方法是不同的,比如_context.Entry()方法在ObjectContext中是没有的。

Entity Framework 数据部分更新之Attach &&Detach的更多相关文章

  1. "Entity Framework数据插入性能追踪"读后总结

    园友莱布尼茨写了一篇<Entity Framework数据插入性能追踪>的文章,我感觉不错,至少他提出了问题,写了出来,引起了大家的讨论,这就是一个氛围.读完文章+评论,于是我自己也写了个 ...

  2. .NET基础篇——Entity Framework 数据转换层通用类

    在实现基础的三层开发的时候,大家时常会在数据层对每个实体进行CRUD的操作,其中存在相当多的重复代码.为了减少重复代码的出现,通常都会定义一个共用类,实现相似的操作,下面为大家介绍一下Entity F ...

  3. asp.net mvc常用的数据注解和验证以及entity framework数据映射

    终于有时间整理一下asp.net mvc 和 entity framework 方面的素材了. 闲话少说,步入正题: 下面是model层的管理员信息表,也是大伙比较常用到的,看看下面的代码大伙应该不会 ...

  4. Entity Framework 数据并发访问错误原因分析与系统架构优化

    博客地址 http://blog.csdn.net/foxdave 本文主要记录近两天针对项目发生的数据访问问题的分析研究过程与系统架构优化,我喜欢说通俗的白话,高手轻拍 1. 发现问题 系统新模块上 ...

  5. 在服务器中使用 Entity Framework 的 Migration 更新数据库

    在开发环境中,每次我们对要对数据库进行更改,比如增加修改表字段等.改好Entity类后,我们只需在Nuget程序包管理控制台运行 update-database 脚本却可: update-databa ...

  6. entity framework 新增,更新,事务

    protected void Button1_Click(object sender, EventArgs e) { yyEntities _db; _db = new yyEntities(); t ...

  7. entity framework 数据加载三种方式的异同(延迟加载,预加载,显示加载)

    三种加载方式的区别 显示加载: 显示加载

  8. Entity Framework 数据生成选项DatabaseGenerated

    在EF中,我们建立数据模型的时候,可以给属性配置数据生成选项DatabaseGenerated,它后有三个枚举值:Identity.None和Computed. Identity:自增长 None:不 ...

  9. Entity Framework 数据生成选项DatabaseGenerated(转)

    在EF中,我们建立数据模型的时候,可以给属性配置数据生成选项DatabaseGenerated,它后有三个枚举值:Identity.None和Computed. Identity:自增长 None:不 ...

随机推荐

  1. iOS极光推送

    昨天花了一下午的时间研究了下极光推送,也前也是没做过,不知道从何下手!才开始的时候一看官方的SDK感觉好难,不过经过一系列的捣鼓之后,手机收到了推送信息,感觉其实并没有那么难! 1.配置开发证书(得有 ...

  2. C#中的多线程-入门

    概述与概念C#支持通过多线程并行地执行代码,一个线程有它独立的执行路径,能够与其它的线程同时地运行.一个C#程序开始于一个单线程,这个单线程是被CLR和操作系统(也称为“主线程”)自动创建的,并具有多 ...

  3. sql中Statement与PreparedStatement的区别

    1.Statement用于执行静态sql语句,在执行时,必须指定一个事先准备好的sql语句,也就是说sql语句是静态的. 2.PrepareStatement是预编译的sql语句对象,sql语句被预编 ...

  4. 使用微信 SDK 上传图片到七牛

    总体思路是:在微信下选好图片后将图片上传到微信服务器,在后端使用微信服务器返回的图片 serverId 加上调用接口的 ApiTicket 通过七牛的 fetch 接口向微信服务器下载多媒体文件的接口 ...

  5. Manifest merger failed : uses-sdk:minSdkVersion 9 cannot be smaller than version 10 declared in library

    Error:Execution failed for task ':app:processDebugManifest'. > Manifest merger failed : uses-sdk: ...

  6. 10个你必须知道的jQueryMobile代码片段

    1.在列表项和按钮上禁用文本截断     如果你的列表项或者按钮上是一个很长的文本,它将会被jQuery Mobile自动截断,要禁用这个截断设置,需要在CSS选择器上添加属性"white- ...

  7. 初学swift笔记-数组、字典、元组(三)

    数组的使用.字典的使用.元组的使用 import Foundation //1.定义数组 //集合数据 数组.字典 ,,,]//常用定义 ,,,]//常用定义 ,,,]//范型定义 ,,,] arr_ ...

  8. STM32与LPC系列ARM资源之比较

    由于有周立公开发板的影响,LPC系列的开发板在工程师心目中一般是入门的最好型号之一.这次刚好有STM32的竞赛,正好将两者的资源进行比较一下(LPC系列以LPC213X为例). LPC213X包括LP ...

  9. yii post delete request more safe

    常规的delete方法如下: /**  * Deletes a particular model. * If deletion is successful, the browser will be r ...

  10. 利用代码改变世界 #AzureDev

    毫无疑问,开发人员是 //build/ 2013 的主角.开发人员是我们这个行业的心脏和灵魂,我们很感谢他们所做的一切.在 Satya Nadella 走上讲台发表第 2 天的主题演讲之前,我们播放了 ...