C# cơ bản .NET Core
(EF Core) Fluent API (Bài trước)
(Bài tiếp) (EF Core) Scaffold

Truy vấn dữ liệu cơ bản với EF Core

Việc thực hiện truy vấn luôn làm việc với Linq, nên đảm bảo thêm namespace System.Linq vào. Hãy copy mã nguồn bài trước (Fluent API), đổi tên thư mục thành ef04 để thực hành.

Truy vấn để lấy dữ liệu từ EF cơ bản viết các câu lệnh LINQ phù hợp trên các nguồn dữ liệu (các DbSet). Sau đây là một số ví dụ:

Ví dụ, lấy tất cả các sản phẩm

Truy vấn dữ liệu trực tiếp từ các DbSet

Với các DbSet (Table) mặc định được giám sát bởi EF, khi truy cập để đọc các phần tử (hàng) nó sẽ tự động truy cấn lấy dữ liệu về. Đồng thời sử dụng các hàm có trong DbSet có thể lọc, giới hạn, tìm kiếm ... Ví dụ, lấy các sản phẩm tử bảng Product

using (var context = new ShopContext ()) {
    var products = context.products;
    // var products = await context.products.ToListAsync (); nếu muốn dùng async
    foreach (var pro in products) {
        Console.WriteLine (pro.Name);
    }
}

Vì các DbSet triển khai từ Queryable, nên có thể dùng trực tiếp nhiều phương thức của nó như: Where, Take, Contain ...

Ví dụ lấy ra 2 sản phẩm, sản sắp xếp giảm dần theo giá, chỉ các sản phẩm có giá trên 100

var products = context.products
                .Where(p => p.Price > 100)              // Lọc các sản phẩm giá trên 100
                .OrderByDescending(p => p.Price)        // Sắp xếp giảm dần, tăng dần là OrderBy
                .Take(2);                               // Chỉ lấy 2 dòng đầu

Ngoài ra bạn có thể sử dụng Sum để tính tổng, Average tính trung bình ...

Để tìm một dòng dữ liệu theo PK Key, thì dùng FindAsync

// Tìm sản phẩm có ID bằng 6
var product = await context.products.FindAsync(6);
if (product !=  null)
    Console.WriteLine($"{product.Name}");

Lấy phần tử đầu tiên thỏa mãn điều kiện

using (var context = new ShopContext())
{
    // Sản phẩm đầu tiên scó giá trên 100, bắt đầu bằng chữ S
    var product = await context.products.FirstOrDefaultAsync(p => (p.Price > 100 && p.Name.StartsWith("S")));
    if (product !=  null)
        Console.WriteLine($"{product.Name}");
}

Bạn có thể viết câu LINQ

var products = await (from p in context.products select p).ToListAsync();
foreach (var pro in products)
{
    Console.WriteLine(pro.Name);
}

Cũng có thể áp dụng kỹ thuật async để duyệt qua từng phần tử.

using (var context = new ShopContext())
{
    var products =  (from p in context.products
                          select p)
                         .ToAsyncEnumerable();

    await products.ForEachAsync(
        p =>
        {
            Console.WriteLine($"{p.Name} - {p.Price}");
        }
    );
}

Truy vấn kết hợp nhiều bảng với join

Sử dụng inner join

// Truy vấn lấy các sản phẩm (tên, giá) và tên danh mục của sản phẩm
var products
    = from p in context.products
      join c in context.categories on p.CategoryId equals c.CategoryId
      // where p.ProductId == 2
      select new {
          tensanpham = p.Name,
          gia = p.Price,
          danhmuc = c.Name
      };



foreach (var item in products)
{
   Console.WriteLine($"{item.tensanpham} giá {item.gia} danh mục {item.danhmuc}");
}

Sử dụng left join

Đầu tiên xem truy vấn sau, lấy sản phẩm và tên danh mục thứ 2 của sản phẩm

var products
    = from p in context.products
      join c in context.categories on p.CategorySecondId equals c.CategoryId
      // where p.ProductId == 2
      select new {
          tensanpham = p.Name,
          gia = p.Price,
          danhmuc = c.Name
      };



foreach (var item in products)
{
   Console.WriteLine($"{item.tensanpham} giá {item.gia} danh mục {item.danhmuc}");
}
// Sản phẩm 2 giá 11.0000 danh mục Cate2
// Sản phẩm 5(1) giá 333.0000 danh mục Cate2

Câu truy vấn trên là inner join, sản phẩm phải có danh mục thứ 2 mới được lấy ra, sản phẩm nào không có danh mục thứ 2 bị loại bỏ. Trong trường hợp, nếu muốn lấy tất cả các sản phẩm, kể cả trường hợp danh mục thứ 2 của nó không tồn tại, thì dùng left join như sau:

// Thi hành DefaultIfEmpty() trên tập kết quả right của Join để thực hiện left join
 var products
    = from p in context.products
      join c in context.categories on p.CategorySecondId equals c.CategoryId into t
      from cate2 in t.DefaultIfEmpty()
      // where p.ProductId == 2
      select new {
          tensanpham = p.Name,
          gia = p.Price,
          danhmuc = (cate2 == null) ? "KHÔNG CÓ" : cate2.Name
      };


foreach (var item in products)
{
   Console.WriteLine($"{item.tensanpham} giá {item.gia} danh mục {item.danhmuc}");
}
// Sản phẩm 4(1) giá 323.0000 danh mục KHÔNG CÓ
// Sản phẩm 3 giá 33.0000 danh mục KHÔNG CÓ
// Sản phẩm 2 giá 11.0000 danh mục Cate2
// Sản phẩm 1 giá 12.0000 danh mục KHÔNG CÓ
// Sản phẩm 5(1) giá 333.0000 danh mục Cate2

Truy vấn dữ với Raw Query

Trên một bảng (nguồn dữ liệu) bạn có thể thi hành trực tiếp câu truy vấn SQL, ví dụ:

using (var context = new ShopContext ()) {
    String sql = "select * from products order by Price Desc";
    var products = context.products.FromSqlRaw(sql);

    await products.ForEachAsync(p => {
        Console.WriteLine(p.Name);
    });
}

Các hàm trong EF

Có các hàm xây dựng sẵn trong EF.Functions. như Like

var products = await (from p in context.products
               where EF.Functions.Like(p.Name, "%phẩm%")
               select p)
               .ToListAsync();

Tham khảo mã nguồn: EF/ef04 hoặc tải về ex044


Đăng ký nhận bài viết mới
(EF Core) Fluent API (Bài trước)
(Bài tiếp) (EF Core) Scaffold