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();
    }
}
posted @ 2018-05-30 09:22  libingql  阅读(2161)  评论(0编辑  收藏  举报