[翻译] - <Entity Framework> - 对象检索
纯属学习上的记录, 非专业翻译, 如有错误欢迎指正!
原文地址: http://msdn.microsoft.com/en-us/library/gg715121(v=vs.103)
实体集合对象类 DbSet, ObjectSet 和它们的泛型版本)的实体提供了一个返回指定类型的所有实体的起始查询. 这个查询可以通过 LINQ to Entitier 方法进一步细化. 这一节将讨论检索数据库或内存中的对象的各种方法.
这一节中的实例程序全部 School 模型.
使用 DbSet.Find 通过主键获得对应的实体
Find 方法使用主键值做为参数来试着从上下文对象跟踪的实体中找到对应的实体. 如果在上下文对象中找不到该实体, 那么一个对数据库中的数据进行评估(判断条件)的查询将会被执行. 如果在上下文对象和数据库中都找不到该实体, 则会返回空值 (null). 需要注意的是, Find 方法有可能返回那些刚被添加到上下文对象中, 但还没同步到数据库上的对象.
下面的代码演示了Find 方法的使用方法:
1 using (var context = new SchoolEntities()) 2 { 3 // 因为 DepartmentID 为 1 的 Department 还没有被载入到 context 中, 故以下操作将会访问数据库 4 var department = context.Departments.Find(1); 5 6 7 8 // 将不再访问数据库就能返回对应的实例 9 var department2 = context.Departments.Find(1); 10 context.Departments.Add(new Department { DepartmentID = -1 }); 11 12 13 // 即使新的 Department 对象还没有被插入到数据库中, 但仍可以通过 Find 方法找到它 14 var newDepartment = context.Departments.Find(-1); 15 }
Find 方法接受一个 object 数组作为参数. 在处理含有多个主键的数据时, 可以按照在概念模型中定义的顺序将所有主键用逗号分隔传入.
使用 DbSet.Find 来查看上下文对象中的数据
通过 DbSet 的 System.Data.Entity.DbSet.Local 属性可以访问那些正被上下文对象跟踪且没有被标记为已删除的对象集合. 也就是说, 访问 Local 属性永远不会引起数据库查询. 这个属性一般在执行了一次数据库查询以后使用. System.Data.Entity.DbExtensions.Load(System.Linq.IQueryable) 扩展方法可以使数据库查询立即被执行, 故上下文对象可以对查询结果进行跟踪. 例如:
1 using (var context = new SchoolEntities()) 2 { 3 // 将数据库中所有的 Department 对象都载入到 context 中 4 context.Departments.Load(); // 译注: 要使用 Load() 方法需先添加对 System.Data.Entity 命名空间的引用 5 6 7 // 向 context 添加一个新的 Department. 8 // 即使该对象还没有被保存到数据库中, 但当访问 Local 属性时, 这个对象将会被包含在结果中返回. 9 context.Departments.Add(new Department { Name = "Mathematics" }); 10 11 12 // 将其中一个已存在的 Department 对象标记为 Deleted. 13 // 则在访问 Local 属性时, 该对象将不会被包含在返回的结果中. 14 context.Departments.Remove(context.Departments.Find(1)); 15 16 17 // 遍历访问 context 中的 Department 对象 18 Console.WriteLine("In Local: "); 19 foreach (var dpt in context.Departments.Local) 20 { 21 // State 属性返回一个 System.Data.EntityState枚举值, 故你必须添加一个对 System.Data.Entity dll 的引用 22 Console.WriteLine("Found {0}: {1} with state {2}", 23 dpt.DepartmentID, dpt.Name, 24 context.Entry(dpt).State); 25 } 26 27 28 // 调用一个对数据库的查询, 在这里, 刚添加到 context 中的 Department 将不会被包含在返回的结果中, 29 30 // 反而刚才被标记为 Deleted 的 Department 则会被包含在其中 31 Console.WriteLine("\nIn DbSet query: "); 32 foreach (var dpt in context.Departments) 33 { 34 Console.WriteLine("Found {0}: {1} with state {2}", 35 dpt.DepartmentID, dpt.Name, 36 context.Entry(dpt).State); ; 37 } 38 }
遍历为继承层次结构中一部分的实体
当概念模型中包含一个类型继承了另一个类型, 则这些类型称为继承层次结构的一部分. 用 LINQ to Entities, 你只需在查询中指定基类的类型, 便可以返回一个包含了继承层次结构中所有类型的实例的集合. 或者你也可以通过一个查询返回派生类的一个实例. 例如: 以下查询是基于一个定义了 OnlineCourse 和 OnsiteCourse 这两个继承了 Course 类的概念模型. 该查询同时返回了 Course, OnlineCourse 和 OnsiteCourse 类型的实例.
1 var query = from c in context.Courses select c;
你也可以通过 OfType<T> 方法指定一个派生类, 使查询只返回该类型的实例. 如以下代码则只返回了 OnlineCourse 类型的实例.
1 var query = from c in context.Courses.OfType<OnlineCourse>() 2 select c;
No-tracking Queries
有时你可能只想对实体进行检索, 但不需要上下文对象对实体进行跟踪. 在对大量的实体进行只读检索时, 这将带来更好的性能. AsNoTracking 扩展方法将执行一个查询, 返回一个不被上下文对象跟踪的结果集. 在接下来的例子中, 这些查询也会返回具体的对象, 但所返回的对象并不会被上下文对象跟踪.
1 // 查询所有的 Department 对象, 但不对他们进行跟踪; 2 3 var departments1 = context.Departments.AsNoTracking().ToList(); 4 5 // 查询一部分 Department 对象, 也不进行跟踪; 6 var departments2 = context.Departments 7 .Where(d => d.Name.StartsWith("math")) 8 .AsNoTracking() 9 .ToList();