《Entity Framework 6 Recipes》中文翻译系列 (11) -----第三章 查询之异步查询
翻译的初衷以及为什么选择《Entity Framework 6 Recipes》来学习,请看本系列开篇
第三章 查询
前一章,我们展示了常见数据库场景的建模方式,本章将向你展示如何查询实体数据模型,一般来说,有三种方式:
1、LINQ to Entities;
2、Entity SQL;
3、Native SQL;
我们将在本章演示这三种方式,为了帮助你理解实体框架查询的基本知识,本章覆盖了常见和不常见的场景。同时我们也展示了实体框架6新的查询功能。
3-1.异步查询
你有一个长耗时的实体框架查询,当执行查询时,你不想打断应用程序主线程运行,在数据返加之前,能让用户做一些别的操作。同时,使用LINQ to Entities来查询模型也一样重要,它是查询数据库模型的首选方案。
解决方案
假设你有如图3-1所示的模型。
图3-1 模型中,一个代表助理的Associate的实体类型和一个代表助理工资历史的AssociateSalary实体
在这个模型中,我们有两个代表助理和他们工资历史的实体。
作为开始,我们在示例中使用Code-First方法创建类,在代码清单3-1中,创建这些实体类。
代码清单3-1 Associate 和 AssociateSalary实体类型
public class Associate
{
public Associate()
{
AssociateSalaries = new HashSet<AssociateSalary>();
}
public int AssociateId { get; set; }
public string Name { get; set; }
public virtual ICollection<AssociateSalary> AssociateSalaries { get; set; }
}
public class AssociateSalary
{
public int SalaryId { get; set; }
public int AssociateId { get; set; }
public decimal Salary { get; set; }
public DateTime SalaryDate { get; set; }
public virtual Associate Associate { get; set; }
}
接下来,代码清单3-2使用Code-First创建DbContext上下文对象,注意在OnModelCreateing方法中,我们显示地将SalaryId属性映射为AssociateSalary表的主键。当我们使用Code Firtst时,如果一个属性的名字是Id或者<表名>Id,实体框架为假定该属性是对应表的主键。另外,像这里这样,要显式设置主键。
代码清单3-2 Dbcontext上下文对象
public class EFRecipesEntities : DbContext
{
public EFRecipesEntities()
: base("ConnectionString")
{
} public DbSet<Associate> Associates { get; set; }
public DbSet<AssociateSalary> AssociateSalaries { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Associate>().ToTable("Chapter3.Associate");
modelBuilder.Entity<AssociateSalary>().ToTable("Chapter3.AssociateSalary"); //显示分配实体键为AssociateSalary表的主键,以免实体框架使用默认映射约定
modelBuilder.Entity<AssociateSalary>().HasKey(x => x.SalaryId);
base.OnModelCreating(modelBuilder);
}
}
代码清单3-3 演示,如何借助新实体框架的异步方法实现异步查询,删除、加载、获取数据。
代码清单3-3.异步处理实体框架查询
private static void Main()
{
var asyncTask = EF6AsyncDemo(); foreach (var c in BusyChars())
{
if (asyncTask.IsCompleted)
{
break;
}
Console.Write(c);
Console.CursorLeft = ;
Thread.Sleep();
}
Console.WriteLine("\nPress <enter> to continue...");
Console.ReadLine();
} private static IEnumerable<char> BusyChars()
{
while (true)
{
yield return '\\';
yield return '|';
yield return '/';
yield return '-';
}
} private static async Task EF6AsyncDemo()
{
await Cleanup();
await LoadData();
await RunForEachAsyncExample();
await RunToListAsyncExampe();
await RunSingleOrDefaultAsyncExampe();
} private static async Task Cleanup()
{
using (var context = new EFRecipesEntities())
{
// 清除原始数据
// 异步执行原始SQL语句
Console.WriteLine("Cleaning Up Previous Test Data");
Console.WriteLine("=========\n"); await context.Database.ExecuteSqlCommandAsync("delete from chapter3.AssociateSalary");
await context.Database.ExecuteSqlCommandAsync("delete from chapter3.Associate");
await Task.Delay();
}
} private static async Task LoadData()
{
using (var context = new EFRecipesEntities())
{
// 添加测试数据
Console.WriteLine("Adding Test Data");
Console.WriteLine("=========\n"); var assoc1 = new Associate { Name = "Janis Roberts" };
var assoc2 = new Associate { Name = "Kevin Hodges" };
var assoc3 = new Associate { Name = "Bill Jordan" };
var salary1 = new AssociateSalary
{
Salary = 39500M,
SalaryDate = DateTime.Parse("8/4/09")
};
var salary2 = new AssociateSalary
{
Salary = 41900M,
SalaryDate = DateTime.Parse("2/5/10")
};
var salary3 = new AssociateSalary
{
Salary = 33500M,
SalaryDate = DateTime.Parse("10/08/09")
};
assoc1.AssociateSalaries.Add(salary1);
assoc2.AssociateSalaries.Add(salary2);
assoc3.AssociateSalaries.Add(salary3);
context.Associates.Add(assoc1);
context.Associates.Add(assoc2);
context.Associates.Add(assoc3); // 异步保存
await context.SaveChangesAsync();
await Task.Delay();
}
} private static async Task RunForEachAsyncExample()
{
using (var context = new EFRecipesEntities())
{
Console.WriteLine("Async ForEach Call");
Console.WriteLine("========="); // 借助 ForEachAsync 方法
await context.Associates.Include(x => x.AssociateSalaries).ForEachAsync(x =>
{
Console.WriteLine("Here are the salaries for Associate {0}:", x.Name); foreach (var salary in x.AssociateSalaries)
{
Console.WriteLine("\t{0}", salary.Salary);
}
});
await Task.Delay();
}
} private static async Task RunToListAsyncExampe()
{
using (var context = new EFRecipesEntities())
{
Console.WriteLine("\n\nAsync ToList Call");
Console.WriteLine("========="); // 借助 ToListAsync 方法
var associates = await context.Associates.Include(x => x.AssociateSalaries).OrderBy(x => x.Name).ToListAsync(); foreach (var associate in associates)
{
Console.WriteLine("Here are the salaries for Associate {0}:", associate.Name);
foreach (var salaryInfo in associate.AssociateSalaries)
{
Console.WriteLine("\t{0}", salaryInfo.Salary);
}
}
await Task.Delay();
}
} private static async Task RunSingleOrDefaultAsyncExampe()
{
using (var context = new EFRecipesEntities())
{
Console.WriteLine("\n\nAsync SingleOrDefault Call");
Console.WriteLine("========="); var associate = await context.Associates.
Include(x => x.AssociateSalaries).
OrderBy(x => x.Name).
FirstOrDefaultAsync(y => y.Name == "Kevin Hodges"); Console.WriteLine("Here are the salaries for Associate {0}:", associate.Name);
foreach (var salaryInfo in associate.AssociateSalaries)
{
Console.WriteLine("\t{0}", salaryInfo.Salary);
}
await Task.Delay();
}
}
代码清单3-3输出如下:
Cleaning Up Previous Test Data
=========
Adding Test Data
=========
Async ForEach Call
=========
Here are the salaries for Associate Janis Roberts:
39500.00
Here are the salaries for Associate Kevin Hodges:
41900.00
Here are the salaries for Associate Bill Jordan:
33500.00
Async ToList Call
=========
Here are the salaries for Associate Bill Jordan:
33500.00
Here are the salaries for Associate Janis Roberts:
39500.00
Here are the salaries for Associate Kevin Hodges:
41900.00
Async SingleOrDefault Call
=========
Here are the salaries for Associate Kevin Hodges:
41900.00
原理
在这个示例中,我们演示了实体框架的两个关键概念的用途:使用LINQ扩展查询模型以及实体框架6中实现的新的异步功能。
对于绝大多数的查询操作,你都需要用到LINQ。这样做会给你带来,智能提示、编译时检查,以及强类型的编程体验。如果你需要在运行时动态构建查询,你可以考虑使用Entity SQL,它能连接查询表达式各个部分的字符串。你将在本节后面看到相关的示例。
开始时,我们先清除之前数据库中的测试数据。请注意我们是如何把Cleanup()操作包装在一个异步方法中的。然后我们生成原始的SQL语句,并调用新的ExecuteSqlCommandAsync()方法。请注意我们是如何凭借.NET framework4.5中的async/await异步模式。这种模式能够不通过显示实例化一个后台线程来实现异步;此外,它释放当前等待数据库操作完成的CLR线程控制权。(译注:也就是不卡住当前线程 ,让它可以继续执行别的操作)。
接下来,我们加载测试数据Associate和AssoicateSalareies。为了执行异步调用,像前面一样,我们将LoadData()操作包装在一个异步方法中,并通过最新增加的SaveChangesAsync()方法在数据库中插入测试数据。
接下为,我们呈现了三种不同的模型查询方式,每种方式都凭借了实体框架中的LINQ扩展,每种方式都凭借await/async模式包含在一个异步方法中。在RunForEachAsyncExample()方法中,由于没有与foreach语句相匹配异步方法,我们使用了ForEachAsync()扩展方法。凭借这个异步方法以及 Inclued()方法,我们能够异步查询和枚举这些对象。
在随后的RunToListAsyncExample()和RunSingeOrDefaultAsyncExample()查询中,我们凭借ToList()和SingleOrDefault()方法的新的异步方法来实现。
实体框架现在公布了大量的异步操作方法。它们的命名约定是,在已存在的api名称中加上后缀Asyn,使其相对简单地在添加或者获取数据时实现异步。
实体框架交流QQ群: 458326058,欢迎有兴趣的朋友加入一起交流
谢谢大家的持续关注,我的博客地址:http://www.cnblogs.com/VolcanoCloud/
《Entity Framework 6 Recipes》中文翻译系列 (11) -----第三章 查询之异步查询的更多相关文章
- 《Entity Framework 6 Recipes》中文翻译系列 (17) -----第三章 查询之分页、过滤和使用DateTime中的日期部分分组
翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 3-12 分页和过滤 问题 你想使用分页和过滤来创建查询. 解决方案 假设你有如图3 ...
- 《Entity Framework 6 Recipes》中文翻译系列 (12) -----第三章 查询之使用SQL语句
翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 3-2使用原生SQL语句更新 问题 你想在实体框架中使用原生的SQL语句,来更新底层 ...
- 《Entity Framework 6 Recipes》中文翻译系列 (13) -----第三章 查询之使用Entity SQL
翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 3-4使用实体SQL查询模型 问题 你想通过执行Entity SQL语句来查询你的实 ...
- 《Entity Framework 6 Recipes》中文翻译系列 (14) -----第三章 查询之查询中设置默认值和存储过程返回多结果集
翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 3-6在查询中设置默认值 问题 你有这样一个用例,当查询返回null值时,给相应属性 ...
- 《Entity Framework 6 Recipes》中文翻译系列 (15) -----第三章 查询之与列表值比较和过滤关联实体
翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 3-8与列表值比较 问题 你想查询一个实体,条件是给定的列表中包含指定属性的值. 解 ...
- 《Entity Framework 6 Recipes》中文翻译系列 (16) -----第三章 查询之左连接和在TPH中通过派生类排序
翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 3-10应用左连接 问题 你想使用左外连接来合并两个实体的属性. 解决方案 假设你有 ...
- 《Entity Framework 6 Recipes》中文翻译系列 (18) -----第三章 查询之结果集扁平化和多属性分组
翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 3-14 结果集扁平化 问题 你有一对多关联的两个实体,你想通过一个查询,获取关联 ...
- 《Entity Framework 6 Recipes》中文翻译系列 (19) -----第三章 查询之使用位操作和多属性连接(join)
翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 3-16 过滤中使用位操作 问题 你想在查询的过滤条件中使用位操作. 解决方案 假 ...
- 《Entity Framework 6 Recipes》翻译系列 (1) -----第一章 开始使用实体框架之历史和框架简述
微软的Entity Framework 受到越来越多人的关注和使用,Entity Framework7.0版本也即将发行.虽然已经开源,可遗憾的是,国内没有关于它的书籍,更不用说好书了,可能是因为EF ...
随机推荐
- godaddy1美元虚拟主机
第一个域名是免费的 ftp连接:新建ftp账号,把配置文件导入相应的ftp客户端(user名可能有问题,使用非加密的模式) SSH连接: 1.开启SSH连接:http://godaddy.idcspy ...
- Java基础知识点4:继承
继承是面向对象编程技术中非常重要的一个基本概念.它背后的基本思想就是:通过已有的类来创建一个新的类,这个新的类可以重用(或继承)已有的类方法:新的类也可以加入新的方法和属性. 在这里我们通过一个实例来 ...
- linux系统swappiness参数在内存与交换分区间优化
http://blog.itpub.net/29371470/viewspace-1250975 swappiness的值的大小对如何使用swap分区是有着很大的联系的.swappine ...
- POJ 2653 Pick-up sticks (线段相交)
题意:给你n条线段依次放到二维平面上,问最后有哪些没与前面的线段相交,即它是顶上的线段 题解:数据弱,正向纯模拟可过 但是有一个陷阱:如果我们从后面向前枚举,找与前面哪些相交,再删除前面那些相交的线段 ...
- React,React Native中的es5和es6写法对照
es6用在React中的写法总结: 在es6还没有完全支持到浏览器的阶段里,已经有很多技术人员开始用es6的写法来超前编程了,因为有转义es6语法的工具帮助下,大家才可大量使用.解析看看es6写法用在 ...
- UTC时间和本地时间的区别
在用AS3的Date时,年月日都有两个api,带UTC和不带UTC的,比如fullYear,fullYearUTC 输出看一下: var date:Date = new Date; trace(dat ...
- travis CI
travis可对多语言持续继承,本文以nodejs 为例. 首先添加文件.travis.yml 中language: node_jsnode_js: - "6" - " ...
- 安卓手机USB网络共享,电脑卡顿、反应慢
1.首先需要把手机连接到电脑,在手机上打开USB网络共享. 2.打开设备管理器 3.在网络适配器中,找到Remote NDIS based Internet Sharing Device,右键更新驱动 ...
- 基于webdriver的jmeter性能测试-通过jmeter实现jar录制脚本的性能测试
续接--基于webdriver的jmeter性能测试-Eclipse+Selenium+JUnit生成jar包 在进行测试前先将用于支持selenium录制脚本运行所需的类包jar文件放到jmeter ...
- 有关JVM配置参数含义
1.参数的含义-vmargs -Xms128M -Xmx512M -XX:PermSize=64M -XX:MaxPermSize=128M-vmargs 说明后面是VM的参数,所以后面的其实都是JV ...