EntityFramework Core笔记:查询数据(3)
1. 基本查询
1.1 加载全部数据
using System.Linq;
using (var context = new LibingContext()) { var roles = context.Roles.ToList(); }
1.2 加载单个实体
using (var context = new LibingContext()) { var role = context.Roles.FirstOrDefault(t => t.RoleID == 1); }
using (var context = new LibingContext()) { var role = context.Roles.Find(1); }
注:Find()根据主键值查询返回单个实体。
1.3 筛选条件
using (var context = new LibingContext()) { var roles = context.Roles .Where(t => t.RoleName == "管理员") .ToList(); }
2. 加载关联数据
Entity Framework Core可以在实体模型中使用导航属性,来加载关联数据。
常见的3中关联数据加载方式:
(1)预先加载(Eager Loading):关联数据作为初始查询的一部分从数据库中加载
(2)显式加载(Explicit Loading):关联数据在后续用到时显式指定从数据中加载
(3)延迟加载(Lazy Loading):关联数据通过导航属性,以透明方式从数据库中加载
2.1 预先加载
使用Include()指定需要包含在查询结果中的关联数据。
using System.Linq; using Microsoft.EntityFrameworkCore;
using (var context = new LibingContext()) { var categories = context.Categories .Include(t => t.Products) .ToList(); }
2.2 显式加载
显式加载通过一个导航属性DbContext.Entry(...)API。
using (var context = new LibingContext()) { var category = context.Categories.Find(1); context.Entry(category) .Collection(t => t.Products) .Load(); category.Products.ForEach(product => { Console.WriteLine("ProductID:{0},ProductName:{1}", product.ProductID, product.ProductName); }); }
显式加载通过相关的实体的聚合运算符,而无需加载到内存的操作。
using (var context = new LibingContext()) { var category = context.Categories.Find(1); int count = context.Entry(category) .Collection(t => t.Products) .Query() .Count(); }
筛选加载到内存的关联实体数据。
using (var context = new LibingContext()) { var category = context.Categories.Find(1); var products = context.Entry(category) .Collection(t => t.Products) .Query() .Where(t => t.UnitPrice >= 10) .ToList(); }
3. 跟踪与非跟踪
3.1 跟踪查询
Entity Framework Core跟踪状态的实体,在检测到改动的情况下,调用SaveChanges()时,将持久保存数据库中。
using (var context = new LibingContext()) { var product = context.Products.Find(1); product.UnitPrice = 100m; context.SaveChanges(); }
3.2 非跟踪查询
非跟踪查询在对查询数据只读情况下,可以加快执行。
using (var context = new LibingContext()) { var products = context.Products .AsNoTracking() .ToList(); }
更改默认跟踪上下文实例级别的行为:
using (var context = new LibingContext()) { context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking; var products = context.Products .ToList(); }
3.3 跟踪与投影
即使查询的结果类型不是实体类型,如果结果包含实体类型它们将仍在默认情况下跟踪。
在下面的查询,它返回匿名类型的实例Category
集将跟踪结果中。
using (var context = new LibingContext()) { var categories = context.Categories .Select(t => new { Category = t, Products = t.Products.Count() }); }
如果结果集不包含任何实体类型,会不执行任何跟踪。
在下面的查询,这将返回一个匿名类型使用某些实体(但不实际实体类型的实例)中的值时,没有任何跟踪执行。
using (var context = new LibingContext()) { var products = context.Products .Select(t => new { ProductID = t.ProductID, PrudctName = t.ProductName }); }
4. 原始SQL查询
EntityFramework Core使用原始SQL查询限制条件:
(1)SQL查询返回字段必须属于实体类型
(2)SQL查询必须返回实体类型的所有属性
4.1 基本原始SQL查询
使用FromSql扩展方法,基于原始的 SQL 查询的 LINQ 查询。
using (var context = new LibingContext()) { var products = context.Products .FromSql("SELECT * FROM [dbo].[Product]") .ToList(); }
使用原始的 SQL 查询来执行存储的过程。
CREATE PROCEDURE USP_GetProducts AS BEGIN SELECT * FROM [dbo].[Product] END
using (var context = new LibingContext()) { var products = context.Products .FromSql("EXECUTE [dbo].[USP_GetProducts]") .ToList(); }
4.2 传递参数
SQL参数化可以防止收到SQL注入攻击。
CREATE PROCEDURE USP_GetProductsByUnitPrice @UnitPrice DECIMAL(18, 2) AS BEGIN SELECT * FROM [dbo].[Product] WHERE [UnitPrice] >= @UnitPrice END
using (var context = new LibingContext()) { decimal unitprice = 100m; var products = context.Products .FromSql("EXECUTE [dbo].[USP_GetProducts] {0}", unitprice) .ToList(); }
using System.Data; using System.Data.SqlClient;
using (var context = new LibingContext()) { var unitprice = new SqlParameter("@UnitPrice", SqlDbType.Decimal); unitprice.Value = 100m; var products = context.Products .FromSql("EXECUTE [dbo].[USP_GetProducts] @UnitPrice", unitprice) .ToList(); }
5. 异步查询
异步操作使用场景:当等待一个比较耗时的操作时,使用异步来释放当前的托管线程而无需等待,不会阻塞当前线程的运行。
异步操作在主应用程序线程以外的线程中执行,应用程序可在异步方法执行其任务时继续执行。
异步查询在数据库中执行查询时可以避免阻止线程。
Entity Framework Core提供的异步查询扩展方法包括:ToListAsync(),ToArrayAsync(),SingleAsync()等。
using System.Threading.Tasks; using Microsoft.EntityFrameworkCore;
public async Task<List<Product>> GetProductsAsync() { using (var context = new LibingContext()) { return await context.Products.ToListAsync(); } }