Entity Framework Core là gì
Giới thiệu về Entity Framework CoreEF 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. Show
Để 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 dotnet add package Microsoft.Extensions.Logging.ConsoleNhữ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 CSDLModel là mô hình hóa các đối tượng dữ liệu trong hệ quản trị CSDL thành các đối tượng lập trình, đó là các lớp (class) tương ứng với các bảng ... 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:
Đây là khai báo một lớp bình thường, chỉ có bổ sung thêm vài thuộc tính mô tả (Attribute) cho lớp, thuộc tính - các Attribute này được sử dụng bởi EF. Tạo Context - DbContextDbContext trong EF là ngữ cảnh làm việc, nó biểu diễn, chứa các thông tin cần thiết của một phiên làm việc với CSDL. Để 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
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ẩn bị SQL Server
hoặc thực hiện theo hướng dẫn
SQL Server trên Docker,
bạn cũng cần nắm rõ kỹ thuật lập trình bất đồng bộ trước, xem tại
Lập trình bất đồng bộ C# await/async
using Microsoft.EntityFrameworkCore;
namespace ef01
{
public class ProductsContext : DbContext
{
// Thuộc tính products kiểu DbSetTừ lớp kế thừa DbContext là ProductsContext có thể tương tác với CSDL bằng cách gọi các phương thức thích hợp trong DbContext, tìm hiểu một số trường hợp đơn giản sau đây. Tạo và xóa DatabaseDbContext 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 là phươnng thức của DatabaseFacade để 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ả. // Tạo Database mydata (tên mydata từ thông tin kết nối) // Gồm tất cả các bảng định nghĩa bởi các thuộc tính kiểu DbSet public static async Task CreateDatabase() { using (var dbcontext = new ProductsContext()) { String databasename = dbcontext.Database.GetDbConnection().Database;// mydata Console.WriteLine("Tạo " + databasename); bool result = await dbcontext.Database.EnsureCreatedAsync(); string resultstring = result ? "tạo thành công" : "đã có trước đó"; Console.WriteLine($"CSDL {databasename} : {resultstring}"); } }Chạy thử phương thức trong hàm Main static async Task Main(string[] args) { await CreateDatabase(); } // Tạo mydata // CSDL mydata : tạo thành côngThi 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 là phươnng thức của DatabaseFacade để xóa CSDL. public static async Task DeleteDatabase() { using (var context = new ProductsContext()) { String databasename = context.Database.GetDbConnection().Database; Console.Write($"Có chắc chắn xóa {databasename} (y) ? "); string input = Console.ReadLine(); // Hỏi lại cho chắc if (input.ToLower() == "y") { bool deleted = await context.Database.EnsureDeletedAsync(); string deletionInfo = deleted ? "đã xóa" : "không xóa được"; Console.WriteLine($"{databasename} {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, SaveChangesAsyncCá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, nó nhận tham số là đối tượng Model cần chèn vào. Sau đó gọi phương thức SaveChangesAsync để thực hiện cập nhật dữ liệu vào Server SQL Chạy thử: static async Task Main(string[] args) { await InsertProduct(); }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 cần chèn vào 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, truy vấn với LINQCá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 (nguồn là các DbSet) public static async Task ReadProducts() { using (var context = new ProductsContext()) { // context.SetLogging(); // Lấy danh sách các sản phẩm trong bảng 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(); // Dùng LINQ để truy vấn đến DbSet products (bảng product) // Lấy các sản phẩm cung cấp bởi CTY A products = await (from p in context.products where (p.Provider == "CTY A") select p ) .ToListAsync(); // Nếu không dùng bất đồng bộ chỗ này, có thể dùng // var pros = from p in context.products where (p.Provider == "CTY A") select p; 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 EFMuố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()) { // Lấy Product có ID sản phẩm chỉ ra var product = await (from p in context.products where (p.ProductId == id) select p).FirstOrDefaultAsync(); // Đổi tên và cập nhật 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 đó, dùng cách cập nhật đối tượng độc lập // Tạo đối tượng var pr = new Product() { ProductId = 4, Name = "Abc" }; // Gắn pr vào context để theo dõi, nó trả vể đối tượng EntityEntryLưu ý, các đối tượng như Product kết quả truy vấn, hoặc được thêm vào ... thì mặc định là được giám sát - theo dõi bởi EF. Khi những đối tượng này thay đổi trạng thái thì context.SaveChanges() sẽ thực hiện các tác vụ dựa theo trạng thái của nó. Mỗi dòng Product trả về từ truy vấn, hoặc thêm vào thì trong EF có một đối tượng EntityEntry tương ứng để để quản lý. Để lấy EntityEntry có thể dùng phương thức Entry, bạn có thể dùng nó để thay đổi trạng thái thủ công, ví dụ để điều chỉnh sự ảnh hưởng khi gọi SaveChange. Ví dụ, loại bỏ không bị giảm sát bởi EF cho đối tượng product nhận được EntityEntryCó một số state gồm: Added, Deleted, Detached, Modified, Unchanged 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(); if (product != null) { context.Remove(product); Console.WriteLine($"Xóa {product.ProductId}"); await context.SaveChangesAsync(); } } }EF Logger hiện thị SQL Query trên terminalNế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.GetInfrastructureEF Logger trong .Net Core 3.xĐối với .Net Core 3.x để thiết lập Logger in thông tin tại console thì cần tạo ra một ILoggerFactory, sau đó thiết lập sử dụng nó ở phương thức OnConfiguring của lớp ProductsContext Đầu tiên hãy đảm bảo cài đặt các Package mới nhất: dotnet add package Microsoft.Extensions.DependencyInjection dotnet add package Microsoft.Extensions.Logging dotnet add package Microsoft.Extensions.Logging.ConsoleTạo ILoggerFactory như sau: ILoggerFactory loggerFactory = LoggerFactory.Create(builder => { builder.AddConsole(); });Mặc định ILoggerFactory này bắt tất cả các sự kiện, nếu muốn thiết lập các category muốn lọc cũng như cấp độ thì gọi thêm phương thức AddFilter khi tạo ILoggerFactory, ví dụ: ILoggerFactory loggerFactory = LoggerFactory.Create(builder => { builder .AddFilter(DbLoggerCategory.Database.Command.Name, LogLevel.Warning) .AddFilter(DbLoggerCategory.Query.Name, LogLevel.Debug) .AddConsole(); });Trường hợp trên thiết lập lọc các log thuộc chuyên mục DbLoggerCategory.Database.Command.Name ở mức độ LogLevel.Warning và chuyên mục DbLoggerCategory.Query.Name ở mức độ LogLevel.Debug Các cấp khác xem tại: LogLevel Các tên category tham khảo đối với EF Logger: DbLoggerCategory.Database.Command, DbLoggerCategory.Database.Connection, DbLoggerCategory.Database.Transaction, DbLoggerCategory.Infrastructure, DbLoggerCategory.Migration, DbLoggerCategory.Model, DbLoggerCategory.Query, DbLoggerCategory.Scaffolding, DbLoggerCategory.Update Ví dụ - thiết lập hoàn chỉnh cho lớp ProductsContext using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; namespace ef01 { public class ProductsContext : DbContext { // Tạo ILoggerFactory public static readonly ILoggerFactory loggerFactory = LoggerFactory.Create(builder => { builder .AddFilter(DbLoggerCategory.Database.Command.Name, LogLevel.Warning) .AddFilter(DbLoggerCategory.Query.Name, LogLevel.Debug) .AddConsole(); } ); private const string connectionString = " ... "; protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { base.OnConfiguring(optionsBuilder); optionsBuilder .UseLoggerFactory(loggerFactory) // - Thiết lập sử Logger .UseSqlServer(connectionString); } public DbSetTham khảo mã nguồn , hoặc tải về ex041
Mục lục bài viết
Entity FrameworkModel đơn giảnTạo DbContextTạo Database, xóa DatabaseChèn dữ liệu vào các bảngĐọc dữ liệu từ bảng DBCập nhật dữ liệuXóa dữ liệuHiện thị SQL Query với Logger EF
ĐĂNG KÝ KÊNH, XEM CÁC VIDEO TRÊN XUANTHULAB
|