### Programming Entity Framework-dbContext 学习笔记 第五章

将图表添加到Context中的方式及容易出现的错误

方法 结果 警告
Add Root 图标中的所有实体将被跟踪,并标记为Added SaveChage 将试图将所有实体插入数据库,即使数据库中已存在该实体
Attach Root 所有实体将被跟踪并标记为Unchanged 新添加的实体将不会被插入数据库,并容易造成主键冲突
Add or Attach Root,then paint state throughout graph 所有的实体将拥有正确的状态值 建议使用 Add Root 而不是Attach Root,以避免新实体的主键冲突

DbEntityEntry类型包含属性来记录实体各个状态的值:

  1. CurrentValues 包含实体所有属性的当前值。
  2. OriginalValues 包含实体属性未被修改前的值。
  3. GetDatabaseValues() 方法返回实体属性目前在数据库中的值。
    注:对于状态为Added 和 Deleted 的实体不包含后两个取值,试图读取时,将引发异常。

用于打印各个属性的代码:

private static void PrintPropertyValues(DbPropertyValues values)
{foreach (var propertyName in values.PropertyNames){Console.WriteLine(" - {0}: {1}", propertyName,values[propertyName]);  }
}

Working with DbPropertyValues for Complex Types

  1. Code First 的默认约定是将不包含主键的实体理解为“复杂类型”,当需要将包含主键的实体定义为“复杂类型”时,可借助[ComplexType]特性进行标注。
  2. 当我们从DbPropertyValues 中获取的值为一个复杂对象时,它将被表示为一个新的 DbPropertyValues 对象。

    下面是一个读取含有复杂属性的 DbPropertyValues 的代码

private static void PrintPropertyValues(DbPropertyValues values, int indent = 1)
{foreach (var propertyName in values.PropertyNames){var value = values[propertyName];if (value is DbPropertyValues){Console.WriteLine("{0}- Complex Property: {1}", string.Empty.PadLeft(indent),propertyName);PrintPropertyValues((DbPropertyValues)value, indent + 1);}else{Console.WriteLine("{0}- {1}: {2}", string.Empty.PadLeft(indent), propertyName, values[propertyName]);}}
}

Copying the Values from DbPropertyValues into an Entity

  1. DbPropertyValues 包含一个 ToObject 方法,可以在不覆盖原有实例的情况下,将所有的值复制到一个新的实例对象。

    注:ToObject 方法只复制标量属性,忽略导航属性。

Changing Values in a DbPropertyValues

  1. DbPropertyValues 不是只读的,可以被修改。当你修改CurrentValues 的值的时候,将改变当前实例的值。

    修改将自动触发 Changes Tracking.

  2. Clone() 方法可以复制所有的DbPropertyValues ,新克隆出来的对象将不会被Change Tracker 跟踪。

Using the SetValues method

  1. 用户在修改了实体的属性值之后,想撤销所有的修改,最简单的方式就是利用 SetValues() 方法,将OriginalValues 中的数据拷贝到 CurrentValues 中。

    代码如下:

 entry.CurrentValues.SetValues(entry.OriginalValues); entry.State = EntityState.Unchanged;//因为SetVaues方法不会自动修改实体的状态,所以需要手动修改。
  1. SetValues方法不尽可以接受DbPropertyValues做为参数,也可以接受其他类型,该方法会自动查找同名属性的值进行覆盖,找不到任何值时,引发异常。
  2. 可以利用SetValues方法实现实体对象的克隆。直接上代码:
private static void CreateDavesCampsite()
{using (var context = new BreakAwayContext()){//从数据库中读取d.Name == "Dave's Dump"的实体var davesDump = (from d in context.Lodgings where d.Name == "Dave's Dump" select d).Single();//新建实体var clone = new Lodging();//添加到追踪,这样才可以进行复制context.Lodgings.Add(clone);//复制,这里传入的就不是DbPropertyValues 的实例context.Entry(clone).CurrentValues.SetValues(davesDump);//修改名称clone.Name = "Dave's Camp";//保存context.SaveChanges();Console.WriteLine("Name: {0}", clone.Name); //output:Dave's CampConsole.WriteLine("Miles: {0}", clone.MilesFromNearestAirport); //32.65Console.WriteLine("Contact Id: {0}", clone.PrimaryContactId); //1//只有名称被修改了。}
}

Working with Individual Properties

你可以使用 Property, Complex, Reference, and Collection 方法去获取或者操作单独的属性:

  • Property 方法可以用来处理 Scalar 和 Complex 属性
  • Complex 方法提供对复杂属性的附加特殊操作
  • Reference 和 Collection 方法用于导航属性
  • 还有一个Member方法,可以用于任何类型的属性。该方法不是强类型的,仅提供对属性通用信息的访问
Working with Scalar Properties

Property方法可以访问属性的原始值,当前值,和是否被修改等信息,该方法具有弱类型和强类型的两个重载。直接上代码:

private static void WorkingWithPropertyMethod()
{using (var context = new BreakAwayContext()){var davesDump = (from d in context.Lodgings where d.Name == "Dave's Dump" select d).Single();//此处会调用强类型的泛型方法,所以后面可以使用lambda表达式var entry = context.Entry(davesDump);//使用lambda表达式访问Name属性entry.Property(d => d.Name).CurrentValue = "Dave's Bargain Bungalows";Console.WriteLine("Current Value: {0}", entry.Property(d => d.Name).CurrentValue);Console.WriteLine("Original Value: {0}", entry.Property(d => d.Name).OriginalValue);Console.WriteLine("Modified?: {0}", entry.Property(d => d.Name).IsModified);}
}

输出结果:
Current Value: Dave's Bargain Bungalows
Original Value: Dave's Dump
Modified?: True

Working with Complex Properties
  1. 提供对复杂属性的操作。

Example 5-20. Accessing change tracking information for a complex property.

private static void WorkingWithComplexMethod()
{using (var context = new BreakAwayContext()){//从数据库检索实体var julie = (from p in context.People where p.FirstName == "Julie" select p).Single();//获取Entryvar entry = context.Entry(julie);//操作复杂属性,这里使用了Property方法操作复杂属性的属性。entry.ComplexProperty(p => p.Address).Property(a => a.State).CurrentValue = "VT";//以上方法可以用以下方法代替entry.Property(p => p.Address.State).CurrentValue = "VT";//又或者entry.Property("Address.State").CurrentValue = "VT";Console.WriteLine("Address.State Modified?: {0}", entry.ComplexProperty(p => p.Address).Property(a => a.State).IsModified); //trueConsole.WriteLine("Address Modified?: {0}", entry.ComplexProperty(p => p.Address).IsModified); //true//链式调用访问复杂属性中包含的复杂属性Console.WriteLine("Info.Height.Units Modified?: {0}", entry.ComplexProperty(p => p.Info).ComplexProperty(i => i.Height).Property(h => h.Units).IsModified);//false}
}

当操作复杂属性的时候,Entity Framework 会跟踪它的状态变化,但是不会追踪它的个别属性的变化,当修改其中任一个单独的属性时,所有属性的状态将变为Modified.

  1. 可以修改复杂属性的值
entry.ComplexProperty(p => p.Address).CurrentValue = new Address { State = "VT" };

该操作将会把整个复杂属性标记为:Modified.

Working with Navigation Properties

Reference and Collection 方法被用户访问导航属性

  • Reference 方法用于访问单个实体
  • Collection 方法用于访问集合属性

这些方法提供以下功能:

  1. 读写导航属性的当前值
  2. 从数据库加载关联数据
  3. 获取导航属性代表的查询(query)
Modifying the value of a navigation property

Example 5-21. Change tracking information for a reference navigation property

private static void WorkingWithReferenceMethod()
{using (var context = new BreakAwayContext()){//从数据库检索Name == "Dave's Dump"的实体对象var davesDump = (from d in context.Lodgings where d.Name == "Dave's Dump" select d).Single();//获取entryvar entry = context.Entry(davesDump);//获取并加载Destination导航属性,Load之前改属性为nullentry.Reference(l => l.Destination).Load();var canyon = davesDump.Destination;//输出导航属性destination 属性Name的当前值Console.WriteLine("Current Value After Load: {0}", entry.Reference(d => d.Destination).CurrentValue.Name);//从数据库检索 Name == "Great Barrier Reef" 的Destination 对象var reef = (from d in context.Destinations where d.Name == "Great Barrier Reef" select d).Single();//将导航属性修改为 reefentry.Reference(d => d.Destination).CurrentValue = reef;//输出修改后导航属性destination 属性Name的值Console.WriteLine("Current Value After Change: {0}", davesDump.Destination.Name);}
}

输出结果:
Current Value After Load: Grand Canyon Current Value
After Change: Great Barrier Reef

Modifying navigation properties with the change tracker

之前,我们在处理标量属性的时候,我们发现,当我们通过Change Tracker修改属性时,不必显示的调用DetectChanges()方法。改变就被跟踪到了。
对于导航属性,同样如此!

Working with collection navigation properties

Example 5-22. Method to explore interacting with a collection property

private static void WorkingWithCollectionMethod()
{using (var context = new BreakAwayContext()){//从数据库检索 Description == "Trip from the database" 的Trip对象var res = (from r in context.Reservations where r.Trip.Description == "Trip from the database" select r).Single();var entry = context.Entry(res);//获取并加载集合导航属性entry.Collection(r => r.Payments).Load();//输出导航属性包含记录数Console.WriteLine("Payments Before Add: {0}", entry.Collection(r => r.Payments).CurrentValue.Count);//添加一条新记录var payment = new Payment { Amount = 245 };//添加到Payments集合,确认被跟踪,这里容易出坑context.Payments.Add(payment);//将新对象添加到导航属性entry.Collection(r => r.Payments).CurrentValue.Add(payment);//输出导航属性包含记录数Console.WriteLine("Payments After Add: {0}", entry.Collection(r => r.Payments).CurrentValue.Count);}
}

输出结果:
Payments Before Add: 1
Payments After Add: 2

和之前的其他属性不同,修改集合导航属性后必须手动调用DetectChanges()方法来跟踪变化

Refreshing an Entity from the Database

Entity Framework 的 DbEntityEntry 对象包含Reload 方法来从数据库中加载最新数据。

Example 5-23. Reloading an entity from the database

private static void ReloadLodging()
{using (var context = new BreakAwayContext()){//从数据库检索数据var hotel = (from d in context.Lodgings where d.Name == "Grand Hotel" select d).Single();//使用原始的SQL语句修改数据库中的值context.Database.ExecuteSqlCommand(@"UPDATE dbo.Lodgings  SET Name = 'Le Grand Hotel' WHERE Name = 'Grand Hotel'");Console.WriteLine("Name Before Reload: {0}", hotel.Name);Console.WriteLine("State Before Reload: {0}", context.Entry(hotel).State);//重新加载数据context.Entry(hotel).Reload();Console.WriteLine("Name After Reload: {0}", hotel.Name);Console.WriteLine("State After Reload: {0}", context.Entry(hotel).State);}
}

数据结果

Name Before Reload: Grand Hotel
State Before Reload: Unchanged
Name After Reload: Le Grand Hotel
State After Reload: Unchanged

如果在从新加载数据之前对实体进行了修改 比如

hotel.Name = "A New Name";  

输出结果将变为:

Name Before Reload: A New Name
State Before Reload: Modified
Name After Reload: Le Grande Hotel
State After Reload: Unchanged

Change Tracking Information and Operations for Multiple Entities

前面操纵的都是单个的实体,接下来我们介绍DbContext.ChangeTracker.Entries 方法,该方法包含两个
重载,一个是泛型的,一个是非泛型的。泛型的方法返回指定类型的记录结合。非泛型的重载
返回一个DbEntityEntry类型的集合,包含所有被追踪的实体。

Example 5-24. Iterating over all entries from the change tracker

private static void PrintChangeTrackerEntries()
{using (var context = new BreakAwayContext()){//从数据库检索Description == "Trip from the database"的Reservations类型的对象var res = (from r in context.Reservations where r.Trip.Description == "Trip from the database" select r).Single();//加载它的集合属性 Paymentscontext.Entry(res).Collection(r => r.Payments).Load();//添加一个新的Paymentres.Payments.Add(new Payment { Amount = 245 });//使用非泛型的方法返回所有被追踪的对象var entries = context.ChangeTracker.Entries();//迭代输出类型和状态foreach (var entry in entries){Console.WriteLine("Entity Type: {0}", entry.Entity.GetType());Console.WriteLine(" - State: {0}", entry.State);}}
}

输出结果

Entity Type: Model.Payment
- State: Added
Entity Type: Model.Reservation
- State: Unchanged
Entity Type: Model.Payment
- State: Unchanged

Using the Change Tracker API in Application Scenarios
Resolving Concurrency Conflicts

默认情况下 Entity Framework 总是更新所有的改变,而不管是不是存在并发冲突,但是你可以
配置你的Model,当并发冲突发生时,抛出一个异常。你可以将一个特定的属性指定为 concurrency token

转载于:https://www.cnblogs.com/jameszh/p/6715460.html

Programming Entity Framework-dbContext 学习笔记第五章相关推荐

  1. 《Go语言圣经》学习笔记 第五章函数

    <Go语言圣经>学习笔记 第五章 函数 目录 函数声明 递归 多返回值 匿名函数 可变参数 Deferred函数 Panic异常 Recover捕获异常 注:学习<Go语言圣经> ...

  2. 2022 最新 Android 基础教程,从开发入门到项目实战【b站动脑学院】学习笔记——第五章:中级控件

    第 5 章 中级控件 本章介绍App开发常见的几类中级控件的用法,主要包括:如何定制几种简单的图形.如何使用几种选择按钮.如何高效地输入文本.如何利用对话框获取交互信息等,然后结合本章所学的知识,演示 ...

  3. 《Android深度探究HAL与驱动开发》学习笔记----第五章

    第五章 搭建S3C6410开发板的测试环境 开发板是开发和学习嵌入式技术的主要硬件设备. 主要学习了搭建S3C6410开发板的测试环境.首先要了解到S3C6410是一款低功耗.高性价比的RISC处理器 ...

  4. muduo学习笔记 - 第五章 高效的多线程日志

    第五章 高效的多线程日志 日志有两种意思: 诊断日志 交易日志 本章讲的是前一种日志,文本的供人阅读的日志,通常用于故障诊断和追踪,也可用于性能分析. 日志通常要记录: 收到的每条消息的id(关键字段 ...

  5. javascript高级程序设计 学习笔记 第五章 上

      第五章   引用类型的值(对象)是引用类型的一个实例.在 ECMAScript 中,引用类型是一种数据结构, 用于将数据和功能组织在一起.它也常被称为类,但这种称呼并不妥当.尽管 ECMAScri ...

  6. css层叠样式表基础学习笔记--第五章 文本属性

    第五章 文本属性 5-01 字间距 5-02 行高 5-03 首行缩进 5-04 水平排列方式 5-05 垂直对齐方式 5-06 文本修饰 5-07 文本阴影 5-08 文本属性重置 5-01 字间距 ...

  7. 程序设计与算法三~C++面向对象程序设计~北大郭炜MOOC学习笔记~第五章:继承与派生(新标准C++程序设计)

    以下内容为笔者手打,望读者珍惜,如有转载还请注明. 第五章 继承与派生 $5.1 继承与派生的概念 $5.1.1 基本概念     在C++中,当定义一个新的类B时,如果发现类B拥有某个已经写好的类A ...

  8. 《谁说菜鸟不会数据分析》学习笔记 第五章数据分析

    第五章 数据分析 5.1 数据分析方法 现状分析 5.1.1 对比分析法 5.1.2 分组分析法 5.1.3 结构分析法 5.1.4 分布分析法 5.1.5 交叉分析法 5.1.6 RFM分析法 5. ...

  9. AE学习笔记——第五章:效果预设和渲染导出

    目录 一:效果与预设的应用 (1)效果的运算顺序 (2)效果的应用 (3)动画预设的使用 二:渲染和输出 (1)使用Adobe Media Encoder渲染 (2)使用AE渲染 A:.avi格式 B ...

最新文章

  1. STM32F103 与 STM32F407引脚兼容问题
  2. 一次使用 Eclipse Memory Analyzer 分析 Tomcat 内存溢出
  3. gitlab + Jenkins
  4. ASP.NET ASHX中获得Session
  5. 6万人砍不下来一部拼多多手机,背后原来是这个原因。
  6. qq linux版本下载官网下载,腾讯QQ For Linux
  7. (36)System Verilog类中方法示例
  8. UTF-8字符集成为Java 18默认字符集?发布周期将至,Java 18现身
  9. mysql alisql,Mysql-03. ubuntu 安装 alisql
  10. 浅析export * from 与 export {default} from用法
  11. 基于51单片机的单词记忆测试器
  12. input密码框显示与隐藏
  13. php用do while实现斐波那契数列,php实现斐波那契数列
  14. VR家装:智慧家装“黑科技”
  15. Deepin 20社区版设置双屏显示
  16. 历年至今TVB剧集目录(持续更新...我已看过的推荐)
  17. 用 texstudio, 外部 pdf 浏览器查看可以正常显示中文, 但是内置的 pdf 浏览器不能显示中文?
  18. 获得网易云音乐歌曲播放的url
  19. [微信支付 ] prepay_id 为空,可能出现的问题?微信支付失败
  20. JavaWeb开发分享:WRO

热门文章

  1. [唐诗]入朝洛堤步月-上官仪
  2. forfiles命令批量删除N天前文件
  3. 在linux中制作IOS文件
  4. linux分区空间不足--lvm逻辑卷的实现过程
  5. 究竟应该怎么调用WCF服务?
  6. 基础篇:如何做一名专业的软件测试工程师
  7. [转]改变UITextField placeHolder颜色、字体
  8. 2013-07-22 IT 要闻速记快想
  9. Oracle触发器和new、old特殊变量
  10. Win7下基于消息安全模式的WCF托管(IIS与WinForm)