EntityFramework Core筆記:查詢資料(3)

libingql發表於2018-05-30

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();
    }
}

相關文章