C# Cơ bản .NET Core §1) Cài đặt, chương trình C# đầu tiên §2) Biến, kiểu dữ liệu và nhập/xuất §3) Toán tử số học và gán §4) So sánh, logic và lệnh if, switch §5) Vòng lặp for, while §6) Phương thức - Method §7) Phương thức - Delegate §8) Lớp - Class §9) Kiểu vô danh và dynamic §10) Biểu thức lambda §11) Event §12) Hàm hủy - Quá tải toán tử - thành viên tĩnh - indexer §13) Lớp lồng nhau - namespace §14) null và nullable §15) Mảng §16) Chuỗi ký tự §17) Tính kế thừa §18) Tính đa hình - abstract - interface §19) Struct và Enum §20) Ngoại lệ Exeption §21) IDisposable - using §22) File cơ bản §23) FileStream §24) Generic §25) Collection - List §26) SortedList §27) Queue / Stack §28) Linkedlist §29) Dictionary - HashSet §30) Phương thức mở rộng §31) ObservableCollection §32) LINQ §33) (Multithreading) async - bất đồng bộ §34) Type §35) Attribute Annotation §36) DI Dependency Injection §37) (Multithreading) Parallel §38) (Networking) HttpClient §39) (Networking) HttpMessageHandler §40) (Networking) HttpListener §41) (Networking) Tcp TcpListenerr/TcpClient §42) (ADO.NET) SqlConnection §43) (ADO.NET) SqlCommand §44) (EF Core) Tổng quan §45) (EF Core) Tạo Model §46) (EF Core) Fluent API §47) (EF Core) Query §48) (EF Core) Scaffold §49) (EF Core) Migration §50) (ASP.NET CORE) Hello World! §51) (ASP.NET CORE) Middleware §52) (ASP.NET CORE) Map - Request - Response §53) (ASP.NET CORE) IServiceCollection - MapWhen §54) (ASP.NET CORE) Session - ISession §55) (ASP.NET CORE) Configuration §56) (ASP.NET CORE MVC) Controller - View

Giới thiệu về Entity Framework Core

EF Core là framework (thư viện khung) để ánh xạ các đơn vị dữ liệu mô tả bằng lớp (đối tượng) vào cơ sở dữ liệu quan hệ, nó cho phép ánh xạ vào các bảng CSDL, tạo CSDL, truy vấn với LINQ, tạo và cập nhật vào database.

Để sử dụng EF Core hãy thêm những package cần thiết vào, chạy các lệnh sau:

dotnet add package System.Data.SqlClient
dotnet add package Microsoft.EntityFrameworkCore
dotnet add package Microsoft.EntityFrameworkCore.SqlServer
dotnet add package Microsoft.EntityFrameworkCore.Design
dotnet add package Microsoft.Extensions.DependencyInjection
dotnet add package Microsoft.Extensions.Logging.Console

Những namespace có thể dùng:

using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Threading.Tasks;

Tạo Model đơn giản, ánh xạ bảng CSDL

Model đó là nơi mô tả các dữ liệu, cách thức dữ liệu được xử lý. Hãy tạo ra một dự án Console trong thư mục ef01 có cài đặt các package trên để thực hành. Ở đây tạo ra một model đơn giản, lớp có tên Product biểu diễn các dòng trong bảng của CDSL, bảng này tên là Products

Trước tiên, lớp này định nghĩa thuần túy gồm các thuộc tính như sau:

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace ef01
{
    public class Product
    {
        public int ProductId {set; get;}
        public string Name {set; get;}
        public string Provider {set; get;}
    }
}

Trước khi sử dụng model Product trong EF Core, hãy bổ sung các thiết lập thông qua các Attribute (sử dụng Sử dụng Attribute) như sau:

  • Thiết lập lớp Product ánh xạ vào bảng Products với thuộc tính Table: [Table("Products")]
  • Trường ProductId Primary key của bảng với thuộc tính [Key]
  • Trường Name bắt buộc phải thiết lập (khác null) dùng thuộc tính [Required], và độ dài tối là là 50 ký tự với thuộc tính [StringLength(50)]
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace ef01
{
    [Table("Products")]
    public class Product
    {
        [Key]
        public int ProductId {set; get;}

        [Required]
        [StringLength(50)]
        public string Name {set; get;}

        [StringLength(50)]
        public string Provider {set; get;}
    }
}

Tạo Context - DbContext

Để thực hiện tạo ra mối liên hệ bảng Products tong CSDL và model, tạo ra Context như sau: Tạo lớp kế thừa DbContext đặt tên là ProductsContext, lớp này mang ý nghĩa như là một CSDL.

Trong đó cần nạp chồng OnConfiguring để cấu hình (thiết lập chuỗi kết nối ...), và tạo ra thuộc tính có kiểu DbSet<Product> chính là bảng trong CSDL

Cần có một SQL Server để kết nối đến, nếu chưa có thì có thể cài đặt nhanh trên Docker xem phần Chuỗi kết nối đến SQL Server
using Microsoft.EntityFrameworkCore;

namespace ef01
{
    public class ProductsContext : DbContext
    {
        // Chuỗi kết nối, có chỉ định tên CSDL sẽ làm việc
        private const string connectionString = "Data Source=localhost,1433;Initial Catalog=mydata;User ID=SA;Password=Password123";

        protected override void  OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            base.OnConfiguring(optionsBuilder);
            optionsBuilder.UseSqlServer(connectionString);
        }

        public DbSet<Product> products {set; get;}   // Bảng Products trong DB
    }
}

Từ lớp kế thừa DbContextProductsContext có thể tương tác với CSDL, tìm hiểu một số trường hợp đơn giản sau đây.

Tạo và xóa Database

DbContext có thuộc tính Database, thuộc tính này là đối tượng kiểu DatabaseFacade, từ đó có thể tạo / xóa database.

EnsureCreatedAsync để tạo ra database, nếu database nó đang không tồn tại, nếu DB đã tồn tại thì không làm gì cả.

using System;
using ef01;

namespace ef01
{
    class Program
    {
        public static async void CreateDatabase() {
            using (var dbcontext = new ProductsContext())
            {
                bool result = await dbcontext.Database.EnsureCreatedAsync();
                string resultstring = result ? "tạo  thành  công" : "đã có trước đó";
                Console.WriteLine($"CSDL - {resultstring}");
            }
        }

        static void Main(string[] args)
        {
            CreateDatabase();
            Console.ReadKey();
        }
    }
}

Thi hành thì nó sẽ tạo ra database, nếu DB đó chưa có! Database này tạo ra có tên mydata, có một bảng tên Products với cấu trúc giống mô tả trong model Product

DeleteDatabase để xóa CSDL.

// Xóa database
public static async void DeleteDatabase()
{
    Console.Write("Có chắc chắn xóa DB (y) ? ");
    string input = Console.ReadLine();
    if (input.ToLower() == "y")
    {
        using (var context = new ProductsContext())
        {
            bool deleted = await context.Database.EnsureDeletedAsync();
            string deletionInfo = deleted ? "đã xóa db" : "không xóa được db";
            Console.WriteLine($"{deletionInfo}");
        }
    }
}

Phương thức EnsureDeletedAsync, EnsureCreatedAsync dùng kỹ thuật async, nếu muốn dùng phiên bản đồng bộ thì là EnsureDeleted, EnsureCreated

Chèn dữ liệu vào các bảng, AddAsync, AddRangeAsync, SaveChangesAsync

Các đối tượng DbContext hay DbSet (như thuộc tính products của lớp ProductContext ở trên) có phương thức AddAsync để bạn chèn đối tượng phù hợp vào DbContext. Sau đó gọi phương thức SaveChangesAsync để thực hiện chèn dữ liệu

// Thực hiện chèn dữ liệu mẫu, 2 sản phẩm
public static async void InsertProduct()
{
    using (var context = new ProductsContext())
    {
        // Dùng đối tượng DbSet để thêm
        await context.products.AddAsync(new Product
        {
            Name = "Sản phẩm 1",
            Provider = "Công ty 1"
        });

        // Dùng context để thêm
        await context.AddAsync(new Product()
        {
            Name = "Sản phẩm 2",
            Provider = "Công ty 1"
        });

        // Thực hiện Insert vào DB các dữ liệu đã thêm.
        int rows = await context.SaveChangesAsync();
        Console.WriteLine($"Đã lưu {rows} sản phẩm");
    }
}

Nếu muốn thêm một lúc nhiều dữ liệu thì dùng AddRangeAsync, nó có thể nhận đối số là mảng các đối tượng.

var p1 = new  Product() {Name = "Sản phẩm 3", Provider = "CTY A"};
var p2 = new  Product() {Name = "Sản phẩm 4", Provider = "CTY A"};
var p3 = new  Product() {Name = "Sản phẩm 5", Provider = "CTY B"};

await context.AddRangeAsync(new object[] {p1, p2, p3});

int rows = await context.SaveChangesAsync();
Console.WriteLine($"Đã lưu {rows} sản phẩm");

Đọc dữ liệu từ bảng, LINQ

Các đối tượng DbSet có phương thức ToListAsync() hay ToArrayAsync() để lấy về tất cả các dữ liệu (List) của bảng. Đặc biệt bạn có thể dùng LINQ ( đọc Linq C#) trên các đối tượng này

public static async Task ReadProducts()
{
    using (var context = new ProductsContext())
    {
        // Lấy List các sản phẩm từ DB
        var products = await context.products.ToListAsync();
        Console.WriteLine("Tất cả sản phẩm");
        foreach (var product in products)
        {
            Console.WriteLine($"{product.ProductId,2} {product.Name,  10} - {product.Provider}");
        }
        Console.WriteLine();
        Console.WriteLine();

        //Sử dụng LINQ trên DbSet (products)
        products = await (from p in context.products
                          where (p.Provider == "CTY A") select p
                         )
                        .ToListAsync();

        Console.WriteLine("Sản phẩm CTY A");
        foreach (var product in products)
        {
            Console.WriteLine($"{product.ProductId,2} {product.Name,  10} - {product.Provider}");
        }
    }
}

Cập nhật dữ liệu trong EF

Muốn cập nhật dữ liệu, chỉ việc thay đổi thuộc tính của đối tượng đọc được, sau đó gọi context.SaveChangesAsync

// Đổi tên sản phẩm có ProductID thành  tên mới
public static async Task RenameProduct(int id, string newName)
{
    using (var context = new ProductsContext())
    {

        // context.SetLogging();
        var product = await (from p in context.products
                          where (p.ProductId == id) select p
                         )
                        .FirstOrDefaultAsync(); // Lấy  Product có  ID  chỉ  ra

        if (product != null)
        {
            product.Name = newName;
            Console.WriteLine($"{product.ProductId,2} có tên mới = {product.Name,  10}");
            await context.SaveChangesAsync();  //Thi hành cập nhật
        }
    }
}

Nếu muốn một đối tượng riêng lẻ, không giám sát - muốn thực hiện cập nhật thì gọi đến phương thức Update của DbSet

context.products.Update(p);

Nếu muốn cập nhật một số trường nào đó

var pr = new Product() {
            ProductId  = 4,
            Name = "Abc"
        };
        var pr_e = context.Attach(pr);
        pr_e.Property(p =>  p.Name).IsModified  = true;
        context.SaveChanges();

Xóa dữ liệu trong EF

Để xóa dữ liệu khỏi DB, chỉ việc yêu cầu xóa đối tượng khỏi DbContext bằng phương thức Remove, rồi gọi SaveChangesAsync để cập nhật

// Xóa sản phẩm có ProductID = id
public static async Task DeleteProduct(int id)
{
    using (var context = new ProductsContext())
    {
        // context.SetLogging();
        var product = await (from p in context.products
                          where (p.ProductId == id) select p
                         )
                        .FirstOrDefaultAsync(); // Lấy  Product có  ID  chỉ  ra

        if (product != null)
        {
            context.Remove(product);
            Console.WriteLine($"Xóa {product.ProductId}");
            await context.SaveChangesAsync();
        }
    }
}

EF Logger hiện thị SQL Query trên terminal

Nếu muốn thật sự các câu truy vấn do EF, Linq sinh ra để tương tác với Database thì thêm loger như sau, thêm vào lớp ProductContext phương thức SetLogging:

using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions .DependencyInjection;
using Microsoft.EntityFrameworkCore.Infrastructure;
/..
        public void SetLogging()
        {
            IServiceProvider provider = this.GetInfrastructure<IServiceProvider>();
            ILoggerFactory loggerFactory = provider.GetService<ILoggerFactory>();
            loggerFactory.AddConsole();
        }
/..
Mã nguồn - Source code
Đăng ký theo dõi ủng hộ kênh