zoukankan      html  css  js  c++  java
  • Entity Framework 4 in Action读书笔记——第七章:持久化对象到数据库:使用SaveChanges持久化实体

    本章内容包括
    持久化修改的对象到数据库
    持久化复杂对象图到数据库
    带有外键和独立关联的持久化

    本章,我们讨论如何在连接和断开连接的情况下插入、更新和删除实体。包括单个对象的更新,例如一个customer和复杂关系图的更新,例如一个order和它的details。本章结束的时候,你就可以使用EF处理更新了。

    让我们开始讨论持久化过程是如何工作的吧。

    7.1 使用SaveChanges持久化实体

    实体持久化是存储实体数据到数据库的过程。触发这个过程很简单,只需要调用ObjectContext类的SaveChanges方法即可。

    下面的代码片段显示了如何使用SaveChanges持久化修改的customer:

    var customer = (Customer)(from c in ctx.Companies
                              where c.CompanyId == 1
                              select c);
    customer.Name = "New Name";
    ctx.SaveChanges();

    使用SaveChanges很简单。但它被调用时,在内部遍历所有处于Modified,Deleted和Added状态的实体,生成合适的SQL语句并在数据库里执行。

    SaveChanges执行持久化实体所需的所有管道。不仅仅同步state manager和实体,还检测dirty实体(处于Added,Modified和Deleted状态的实体),启动与数据库的连接和事务,生成正确的SQL,以及提交或者回滚操作。最终,它移除deleted的实体,设置added和modified的实体为Unchanged。最后,这是一个复杂的过程,需要使用数据库,state manager和SQL完成任务,如下图所示:

    SaveChanges方法持久化实体状态的执行步骤

    下面让我们看看每一步,从第一个开始。

    7.1.1 检测dirty实体

    Dirty实体是处于Added,Modified或者Deleted状态的实体。第六章已经知道了,实体和它们关联的实体在state manager中并不总是同步的。SaveChanges方法需要同步它们。

    这一步是持久化过程中最简单的。SaveChanges方法调用DetectChanges方法(第六章介绍了)使实体和它们关联的实体同步。当DetectChanges结束工作,SaveChanges方法为处于Added,Modified和Deleted状态的实体查询state manager检索entry,以便可以持久化它们。
    看下面的代码摘录:

    DetectChanges();
    var entries = ObjectStateManager.GetObjectStateEntries(
    EntityState.Added | EntityState.Modified | EntityState.Deleted);

    由查询state manager返回的entry首先包含added实体,其次是modified实体,最后是deleted实体。

    7.1.2 启动数据库事务

    持久化过程的这一步,SaveChanges打开数据库的连接,开启数据库事务。在下一阶段执行的所有命令都在事务的上下文中执行。

    注意 第8章学习如何自定义事务管理

    这一阶段很简单。我们继续讨论最复杂的一个阶段。

    7.1.3 SQL代码生成和执行

    SQL代码生成和检测dirty实体或者开启事务比起来复杂的多。这里通过遍历调用GetObjectStateEntries方法返回的entry,为它里面的每一个实体生成合适的SQL代码。

    当持久化Added状态的实体时,生成的SQL代码不难,只是一个简单的INSERT SQL语句。

    持久化Modified状态的实体就会变得复杂了。因为state manager保持跟踪每个加载实体的原值和当前值,EF生成只更新修改的属性的UPDATE命令。这是一个伟大的优化,节省了很多工作。

    最简单的SQL代码可能是为处于Deleted状态生成的DELETE命令。SQL代码使用key属性删除一个对象。

    SQL的生成和执行是一个迭代过程,因为SQL语句经常需要使用前面的数据。例如,order和它的detail。插入每一个detail,EF需要之前保存的order的ID,所以只有order已经持久化后才生成order detail的SQL代码。

    7.1.4 数据库事务提交或回滚

    如果上一步的每个SQL命令都正确执行,数据库事务就会提交。但是在SQL语句执行时出现一个错误,事务就会被回滚。

    错误出现的原因有很多。例如,数据库临时断开或者网络问题。这些都是常见的硬件问题,软件问题的处理方式完全相同。重复键或者不可空的列接受了一个null值都会导致执行流程中断,事务回滚。

    这些错误都是有数据库引起的,即使数据库没有引发异常,但是还有其他类型的错误导致持久化过程的突然中止,:并发异常。这是软件异常,它由EF自身引发。我们在第8章讨论并发。

    7.1.5 提交实体

    默认情况下,如果事务正常结束,上下文调用AcceptAllChanges方法。在其调用之后,entry就和实体和数据库同步了,所以你可以认为这是一个实体提交。处于Added或者Modified状态的实体变成Unchanged,Deleted状态的实体从上下文中移除。

    你可以使用SaveChanges的重载操作这个提交过程。SaveChanges的重载接收一个SaveOption(命名空间为:System.Data.Objects)类型的枚举。它有三个可能的值:

    • None—DetectChanges和AcceptAllChanges两个方法都不调用。
    • AcceptAllChangesAfterSave—调用AcceptAllChanges。
    • DetectChangesBeforeSave—在saving changes之前调用DetectChanges。

    这个枚举是一个标识语法,所以可以组合值。

    注意 没有参数传递给SaveChanges时,AcceptAllChangesAfterSave和DetectChangesBeforeSave自动传递。

    在前面有提到,如果在持久化期间出现错误,事务就会回滚。这种情况下,AcceptAllChanges不会被触发,所以如果再次调用SaveChanges方法,上下文会再一次尝试持久化实体,当出现异常时会以同样的方式处理。

    如果在持久化期间没有出现错误,AcceptAllChangesAfterSave不会传递给SaveChanges方法,state manager里的实体和entry保持不变,所以对SaveChanges的再次调用会再次触发持久化。

    7.1.6 重写SaveChanges

    SaveChanges是virtual的,可以在上下文中加入任何你需要的逻辑重写它,甚至完全重写持久化逻辑。重写SaveChanges对构建一个记录系统非常有用。它还可以用于调用实体上的方法,当更新、添加或删除时就通知它。这不能完成,尤其是这个方法通过接口或者基类公开。

    注意 如果不想完全重写SaveChanges逻辑,记住调用基本实现。

    现在你已经掌握了EF如何持久化实体所有基础知识。下面一节,在实际中看看这些概念,看看它们是如何影响数据库的。

    作者:BobTian
    出处http://nianming.cnblogs.com/
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
    欢迎访问我的个人博客:程序旅途
  • 相关阅读:
    使用iScroll时,input等不能输入内容的解决方法
    用jquery 写的类似微博发布的效果
    jq 中each的用法 (share)
    Android SDK 安装中组件的离线安装方法 (share)
    HTML5开发手机应用viewport的作用
    Android开发环境搭建及配置phoneGap
    flipsnap手机屏幕水平滑动框架
    解读网站PR值
    文档碎片
    解读SEO 黑帽白帽 (share)
  • 原文地址:https://www.cnblogs.com/nianming/p/2240813.html
Copyright © 2011-2022 走看看