Entity Framework Core toàn tập
Entity Framework Core là phiên bản mới của Entity Framework sau EF 6.x. Nó là mã nguồn mở, nhẹ, có thể mở rộng và là phiên bản đa nền tảng của công nghệ truy cập dữ liệu Entity Framework.
Entity Framework là một framework Object/Relational Mapping (O/RM – ánh xạ quan hệ/đối tượng). Đây là một cải tiến của ADO.NET, cung cấp cho các nhà phát triển một cơ chế tự động để truy cập và lưu trữ dữ liệu trong cơ sở dữ liệu.
EF Core được dự định sẽ sử dụng với các ứng dụng .NET Core. Tuy nhiên, nó cũng có thể được sử dụng với các ứng dụng dựa trên .NET Framework 4.5+ tiêu chuẩn.
Hình dưới đây minh họa các loại ứng dụng được hỗ trợ, .NET Framework và HĐH.
Lịch sử phiên bản Entity Framework Core
Phiên bản EF Core | Ngày phát hành |
---|---|
Entity Framework Core 5.0 | Tháng 11 – 2020 (dự kiến) |
Entity Framework Core 3.1 | Tháng 12 – 2019 |
Entity Framework Core 3.0 | Tháng 9 – 2019 |
Entity Framework Core 2.2 | Tháng 12 – 2018 |
Entity Framework Core 2.1 | Tháng 5 – 2018 |
Entity Framework Core 2.0 | Tháng 8 – 2017 |
Entity Framework Core 1.1 | Tháng 11 – 2016 |
Entity Framework Core 1.0 | Tháng 6 – 2016 |
Mã nguồn Entity Framework Core trên GitHub: https://github.com/aspnet/EntityFrameworkCore
Lộ trình phát triển Entity Framework Core: docs.microsoft.com/en-us/ef/core/what-is-new/roadmap
Theo dõi các vấn đề của Entity Framework Core tại: https://github.com/aspnet/EntityFrameworkCore/issues
Tài liệu chính thức của Entity Framework Core: https://docs.microsoft.com/ef/core
Cách tiếp cận phát triển của EF Core
EF Core hỗ trợ hai cách tiếp cận phát triển: Code First và Database First. EF Core chủ yếu nhắm vào cách tiếp cận Code First và cung cấp ít hỗ trợ cho cách tiếp cận Database First vì trình thiết kế trực quan hoặc trình hướng dẫn cho mô hình DB không được hỗ trợ kể từ EF Core 2.0.
Theo cách tiếp cận Code First, EF Core API tạo cơ sở dữ liệu và các bảng bằng cách sử dụng chuyển đổi (migration) dựa trên các quy ước và cấu hình được cung cấp trong các lớp thực thể của bạn. Cách tiếp cận này rất hữu ích trong thiết kế hướng miền (Domain Driven Design – DDD).
Theo cách tiếp cận Database First, EF Core API tạo các lớp thực thể và Context dựa trên cơ sở dữ liệu hiện có của bạn bằng cách sử dụng các lệnh của EF Core. Điều này được hỗ trợ hạn chế trong EF Core vì nó không hỗ trợ trình thiết kế trực quan hoặc trình hướng dẫn.
EF Core với EF 6
Entity Framework Core là phiên bản mới và cải tiến của Entity Framework cho các ứng dụng .NET Core. EF Core là phiên bản mới hoàn toàn, vì vậy nó vẫn chưa đầy đủ như EF 6.
EF Core tiếp tục hỗ trợ các tính năng và khái niệm giống như EF 6 như sau:
- DbContext và Dbset.
- Mô hình dữ liệu.
- Truy vấn bằng cách sử dụng Linq-to-Entities.
- Theo dõi thay đổi.
- SaveChanges.
- Chuyển đổi (Migration).
EF Core dần dần sẽ có hầu hết các tính năng của EF 6. Tuy nhiên, có một số tính năng của EF 6 không được hỗ trợ trong EF Core 2.0, chẳng hạn như:
- EDMX/Graphical Visualization của mô hình.
- Trình hướng dẫn mô hình dữ liệu thực thể (cho phương pháp Database First).
- ObjectContext API.
- Truy vấn bằng cách sử dụng Entity SQL.
- Chuyển đổi tự động.
- Kế thừa: Bảng trên mỗi kiểu (TPT)
- Kế thừa: Bảng trên mỗi lớp con (TPC)
- Mối quan hệ nhiều-nhiều.
- Chia tách thực thể.
- Kiểu dữ liệu không gian.
- Ánh xạ stored procedure với DbContext cho hoạt động CUD (Create, Update, Delete).
- Seed data.
EF Core có các tính năng mới sau đây không được hỗ trợ trong EF 6.x:
- Cấu hình mối quan hệ dễ dàng
- Các thao tác INSERT, UPDATE và DELETE hàng loạt.
- Trình cung cấp trong bộ nhớ để thử nghiệm.
- Hỗ trợ cho IoC (Đảo ngược sự phụ thuộc).
- Ràng buộc duy nhất (unique contraints).
- Thuộc tính ẩn (shadow property).
- Khóa thay thế.
- Bộ lọc truy vấn toàn cục.
- Ánh xạ trường.
- DbContext chung
- Các mẫu tốt hơn để xử lý các biểu đồ thực thể bị ngắt kết nối
Tìm hiểu thêm về sự khác biệt của EF Core và EF 6 tại đây.
Trình cung cấp cơ sở dữ liệu của EF Core
Entity Framework Core sử dụng mô hình trình cung cấp để truy cập nhiều loại cơ sở dữ liệu khác nhau. EF Core có các trình cung cấp dưới dạng các gói NuGet mà bạn cần cài đặt.
Bảng sau liệt kê một số trình cung cấp cơ sở dữ liệu và các gói NuGet cho EF Core.
Database | NuGet Package |
---|---|
SQL Server | Microsoft.EntityFrameworkCore.SqlServer |
MySQL | MySql.Data.EntityFrameworkCore |
PostgreSQL | Npgsql.EntityFrameworkCore.PostgreSQL |
SQLite | Microsoft.EntityFrameworkCore.SQLite |
SQL Compact | EntityFrameworkCore.SqlServerCompact40 |
In-memory | Microsoft.EntityFrameworkCore.InMemory |
Cài đặt Entity Framework Core
Entity Framework Core có thể được sử dụng với các ứng dụng dựa trên .NET Core hoặc .NET Framework 4.6. Ở phần này, bạn sẽ tìm hiểu cách cài đặt và sử dụng Entity Framework Core 2.0 trong các ứng dụng .NET Core bằng Visual Studio 2017.
EF Core không phải là một phần của .NET Core và .NET Framework tiêu chuẩn. Nó là một gói NuGet. Bạn cần cài đặt các gói NuGet cho hai thành phần sau đây để sử dụng EF Core trong ứng dụng của bạn:
- Trình cung cấp cơ sở dữ liệu của EF Core.
- Công cụ EF Core.
Cài đặt trình cung cấp cơ sở dữ liệu của EF Core
Như đã đề cập trong phần trước, EF Core cho phép chúng ta truy cập cơ sở dữ liệu thông qua mô hình trình cung cấp.
Có các trình cung cấp cơ sở dữ liệu EF Core cho các cơ sở dữ liệu khác nhau. Các trình cung cấp này có sẵn dưới dạng các gói NuGet.
Trước tiên, chúng ta cần cài đặt gói NuGet cho trình cung cấp cơ sở dữ liệu mà chúng ta muốn truy cập. Ở đây, chúng tôi muốn truy cập cơ sở dữ liệu MS SQL Server, vì vậy chúng tôi cần cài đặt gói NuGet Microsoft.EntityFrameworkCore.SqlServer
.
Để cài đặt gói NuGet của trình cung cấp DB, bạn nhấp chuột phải vào dự án trong Solution Explorer trong Visual Studio và chọn Manage NuGet Packages.. (hoặc chọn trên menu: Tools -> NuGet Package Manager -> Manage NuGet Packages For Solution).
Điều này sẽ mở giao diện trình quản lý gói NuGet. Nhấp vào tab Browse hoặc tab Updates và tìm kiếm Microsoft.entityframeworkcore trong hộp tìm kiếm ở góc trên cùng bên trái, như hình ảnh bên dưới.
Chọn trình cung cấp cho cơ sở dữ liệu bạn muốn truy cập. Trong trường hợp này, chọn Microsoft.EntityFrameworkCore.SqlServer
cho MS SQL Server như hình trên. (đảm bảo rằng nó có logo .NET và tác giả là Microsoft). Nhấp vào Install để bắt đầu cài đặt.
Cửa sổ xem trước hiển thị danh sách các gói sẽ cài đặt trong ứng dụng của bạn. Xem lại các thay đổi và nhấp vào OK.
Cuối cùng, chấp nhận các điều khoản cấp phép liên quan đến các gói sẽ được cài đặt.
Điều này sẽ cài đặt gói Microsoft.EntityFrameworkCore.SqlServer
. Kiểm tra nó trong Dependencies -> NuGet, như hình ảnh bên dưới.
Lưu ý: gói NuGet của trình cung cấp cũng đã cài đặt các gói phụ thuộc khác như
Microsoft.EntityFrameworkCore.Relational
vàSystem.Data.SqlClient
.
Ngoài ra, bạn cũng có thể cài đặt gói NuGet của trình cung cấp bằng Package Manager Console. Chuyển đến Tools -> NuGet Package Manager -> Package Manager Console và thực hiện lệnh sau để cài đặt gói trình cung cấp SQL Server:
PM> Install-Package Microsoft.EntityFrameworkCore.SqlServer
Cài đặt công cụ của EF Core
Cùng với gói trình cung cấp DB, bạn cũng cần cài đặt các công cụ EF để thực thi các lệnh EF Core.
Điều này giúp dễ dàng thực hiện một số nhiệm vụ liên quan đến EF Core trong dự án của bạn tại thời điểm thiết kế, chẳng hạn như chuyển đổi, scaffolding, v.v.
Công cụ EF có sẵn dưới dạng các gói NuGet. Bạn có thể cài đặt gói NuGet cho các công cụ EF tùy thuộc vào nơi bạn muốn thực thi các lệnh: sử dụng Package Manager Console (phiên bản PowerShell của các lệnh EF Core) hoặc sử dụng dotnet CLI.
Cài đặt công cụ EF Core cho PMC
Để thực thi các lệnh EF Core từ Package Manager Console, hãy tìm kiếm gói Microsoft.EntityFrameworkCore.Tools
từ NuGet UI và cài đặt nó như hình ảnh bên dưới.
Điều này sẽ cho phép bạn thực thi các lệnh EF Core cho scaffolding, chuyển đổi, vv trực tiếp từ Package Manager Console (PMC) trong Visual Studio.
Cài đặt công cụ EF Core cho dotnet CLI
Nếu bạn muốn thực thi các lệnh EF Core từ CLI (Giao diện dòng lệnh) của .NET Core, trước tiên hãy cài đặt gói NuGet Microsoft.EntityFrameworkCore.Tools.DotNet
bằng NuGet UI.
Sau khi cài đặt gói Microsoft.EntityFrameworkCore.Tools.DotNet
, chỉnh sửa file .csproj bằng cách nhấp chuột phải vào dự án trong Solution Explorer và chọn Edit <projectname>.csproj. Thêm node <DotNetCliToolReference>
như ví dụ dưới đây. Đây là một bước bổ sung mà bạn cần thực hiện để thực thi các lệnh EF Core 2.0 từ dotnet CLI trong Visual Studio 2017.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="2.0.0" />
<DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.0.0" />
</ItemGroup>
</Project>
Bây giờ, hãy mở dấu nhắc lệnh (hoặc thiết bị đầu cuối như PowerShell chẳng hạn) từ thư mục gốc của dự án của bạn và thực hiện các lệnh EF Core từ CLI bắt đầu bằng lệnh dotnet ef, như hình ảnh bên dưới.
Tạo mô hình từ database có sẵn trong EF Core
Ở phần này bạn sẽ tìm hiểu cách tạo lớp Context và các lớp thực thể cho cơ sở dữ liệu có sẵn trong Entity Framework Core. Tạo các lớp thực thể và Context cho cơ sở dữ liệu có sẵn được gọi là phương pháp tiếp cận Database First.
EF Core không hỗ trợ trình thiết kế trực quan cho mô hình DB và trình hướng dẫn để tạo các thực thể và các lớp Context tương tự như EF 6.
Vì vậy, chúng ta cần thực hiện kỹ thuật đảo ngược bằng cách sử dụng lệnh Scaffold-DbContext
. Lệnh đảo ngược này tạo ra các lớp thực thể và Context (bằng cách kế thừa từ lớp DbContext
) dựa trên lược đồ của cơ sở dữ liệu hiện có.
Chúng ta sẽ tạo các lớp thực thể và Context cho cơ sở dữ liệu SchoolDB sau trong MS SQL Server như hình ảnh bên dưới.
Lệnh Scaffold-DbContext
Sử dụng lệnh Scaffold-DbContext
để tạo một mô hình dựa trên cơ sở dữ liệu hiện tại của bạn. Các tham số sau có thể được chỉ định cho Scaffold-DbContext trong Package Manager Console:
Scaffold-DbContext [-Connection] [-Provider] [-OutputDir] [-Context] [-Schemas>] [-Tables>]
[-DataAnnotations] [-Force] [-Project] [-StartupProject] [<CommonParameters>]
Trong Visual Studio, chọn menu Tools -> NuGet Package Manger -> Package Manger Console và chạy lệnh sau:
PM> Scaffold-DbContext "Server=.SQLExpress;Database=SchoolDB;Trusted_Connection=True;" Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models
Trong lệnh trên, tham số đầu tiên là một chuỗi kết nối bao gồm ba phần: Máy chủ DB, tên cơ sở dữ liệu và thông tin bảo mật.
Ở đây, Server=.SQLExpress;
đề cập đến máy chủ cơ sở dữ liệu SQLEXPRESS cục bộ. Database=SchoolDB;
chỉ định tên cơ sở dữ liệu “SchoolDB” mà chúng ta sẽ tạo các lớp. Trusted_Connection=True;
chỉ định xác thực Windows. Nó sẽ sử dụng thông tin đăng nhập Windows để kết nối với SQL Server.
Tham số thứ hai là tên nhà cung cấp. Chúng tôi sử dụng nhà cung cấp cho SQL Server, vì vậy nó là Microsoft.EntityFrameworkCore.SqlServer
.
Tham số -OutputDir
mô tả thư mục nơi mà chúng tôi muốn tạo ra tất cả các lớp thực thể, đó là thư mục Models.
Sử dụng lệnh sau để xem chi tiết về lệnh Scaffold-DbContext
:
PM> get-help scaffold-dbcontext –detailed
Lệnh trên Scaffold-DbContext
tạo các lớp thực thể cho mỗi bảng trong cơ sở dữ liệu SchoolDB
và lớp Context với các cấu hình Fluent API cho tất cả các thực thể trong thư mục Models.
Sau đây là lớp thực thể Student
được tạo cho bảng Student
.
using System;
using System.Collections.Generic;
namespace EFCoreTutorials.Models
{
public partial class Student
{
public Student()
{
StudentCourse = new HashSet<StudentCourse>();
}
public int StudentId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int? StandardId { get; set; }
public Standard Standard { get; set; }
public StudentAddress StudentAddress { get; set; }
public ICollection<StudentCourse> StudentCourse { get; set; }
}
}
Sau đây là lớp SchoolDBContext
mà bạn có thể sử dụng để lưu hoặc truy xuất dữ liệu.
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;
namespace EFCoreTutorials.Models
{
public partial class SchoolDBContext : DbContext
{
public virtual DbSet<Course> Course { get; set; }
public virtual DbSet<Standard> Standard { get; set; }
public virtual DbSet<Student> Student { get; set; }
public virtual DbSet<StudentAddress> StudentAddress { get; set; }
public virtual DbSet<StudentCourse> StudentCourse { get; set; }
public virtual DbSet<Teacher> Teacher { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
#warning To protect potentially sensitive information in your connection string, you should move it out of source code. See http://go.microsoft.com/fwlink/?LinkId=723263 for guidance on storing connection strings.
optionsBuilder.UseSqlServer(@"Server=.SQLExpress;Database=SchoolDB;Trusted_Connection=True;");
}
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Course>(entity =>
{
entity.Property(e => e.CourseName)
.HasMaxLength(50)
.IsUnicode(false);
entity.HasOne(d => d.Teacher)
.WithMany(p => p.Course)
.HasForeignKey(d => d.TeacherId)
.OnDelete(DeleteBehavior.Cascade)
.HasConstraintName("FK_Course_Teacher");
});
modelBuilder.Entity<Standard>(entity =>
{
entity.Property(e => e.Description)
.HasMaxLength(50)
.IsUnicode(false);
entity.Property(e => e.StandardName)
.HasMaxLength(50)
.IsUnicode(false);
});
modelBuilder.Entity<Student>(entity =>
{
entity.Property(e => e.StudentId).HasColumnName("StudentID");
entity.Property(e => e.FirstName)
.HasMaxLength(50)
.IsUnicode(false);
entity.Property(e => e.LastName)
.HasMaxLength(50)
.IsUnicode(false);
entity.HasOne(d => d.Standard)
.WithMany(p => p.Student)
.HasForeignKey(d => d.StandardId)
.OnDelete(DeleteBehavior.Cascade)
.HasConstraintName("FK_Student_Standard");
});
modelBuilder.Entity<StudentAddress>(entity =>
{
entity.HasKey(e => e.StudentId);
entity.Property(e => e.StudentId)
.HasColumnName("StudentID")
.ValueGeneratedNever();
entity.Property(e => e.Address1)
.IsRequired()
.HasMaxLength(50)
.IsUnicode(false);
entity.Property(e => e.Address2)
.HasMaxLength(50)
.IsUnicode(false);
entity.Property(e => e.City)
.IsRequired()
.HasMaxLength(50)
.IsUnicode(false);
entity.Property(e => e.State)
.IsRequired()
.HasMaxLength(50)
.IsUnicode(false);
entity.HasOne(d => d.Student)
.WithOne(p => p.StudentAddress)
.HasForeignKey<StudentAddress>(d => d.StudentId)
.HasConstraintName("FK_StudentAddress_Student");
});
modelBuilder.Entity<StudentCourse>(entity =>
{
entity.HasKey(e => new { e.StudentId, e.CourseId });
entity.HasOne(d => d.Course)
.WithMany(p => p.StudentCourse)
.HasForeignKey(d => d.CourseId)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("FK_StudentCourse_Course");
entity.HasOne(d => d.Student)
.WithMany(p => p.StudentCourse)
.HasForeignKey(d => d.StudentId)
.HasConstraintName("FK_StudentCourse_Student");
});
modelBuilder.Entity<Teacher>(entity =>
{
entity.Property(e => e.StandardId).HasDefaultValueSql("((0))");
entity.Property(e => e.TeacherName)
.HasMaxLength(50)
.IsUnicode(false);
entity.HasOne(d => d.Standard)
.WithMany(p => p.Teacher)
.HasForeignKey(d => d.StandardId)
.OnDelete(DeleteBehavior.Cascade)
.HasConstraintName("FK_Teacher_Standard");
});
}
}
}
Lưu ý: EF Core chỉ tạo các lớp thực thể cho các bảng chứ không tạo cho Stored Procedure hoặc View.
DotNet CLI
Nếu bạn sử dụng giao diện dòng lệnh dotnet để thực thi các lệnh EF Core thì hãy mở dấu nhắc lệnh và điều hướng đến thư mục gốc của dự án và thực hiện lệnh dotnet ef dbcontext scaffold
sau:
> dotnet ef dbcontext scaffold "Server=.SQLEXPRESS;Database=SchoolDB;Trusted_Connection=True;" Microsoft.EntityFrameworkCore.SqlServer -o Models
Như vậy là bạn có thể tạo mô hình EF Core cho cơ sở dữ liệu có sẵn.
Lưu ý: Khi bạn đã tạo mô hình, bạn phải sử dụng các lệnh chuyển đổi (migration) bất cứ lúc nào bạn thay đổi mô hình để giữ cho cơ sở dữ liệu được cập nhật với mô hình.
DbContext trong Entity Framework Core
Lớp DbContext là một phần không thể thiếu của Entity Framework. Một thể hiện của DbContext
đại diện cho một phiên làm việc với cơ sở dữ liệu có thể được sử dụng để truy vấn và lưu các thể hiện của các thực thể của bạn vào cơ sở dữ liệu.
DbContext
là sự kết hợp của các mẫu Unit Of Work và Repository. DbContext
trong EF Core cho phép chúng ta thực hiện các tác vụ sau:
- Quản lý kết nối cơ sở dữ liệu.
- Cấu hình mô hình và mối quan hệ.
- Truy vấn cơ sở dữ liệu.
- Lưu dữ liệu vào cơ sở dữ liệu.
- Cấu hình theo dõi thay đổi.
- Bộ nhớ đệm.
- Quản lý giao dịch.
Để sử dụng DbContext
trong ứng dụng, chúng ta cần tạo lớp kế thừa từ lớp DbContext
, còn được gọi là lớp Context.
Lớp Context này thường bao gồm các thuộc tính Dbset <TEntity> cho mỗi thực thể trong mô hình. Hãy xem ví dụ sau mình họa về lớp Context trong EF Core.
public class SchoolContext : DbContext
{
public SchoolContext()
{
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
}
//entities
public DbSet<Student> Students { get; set; }
public DbSet<Course> Courses { get; set; }
}
Trong ví dụ trên, lớp SchoolContext
có nguồn gốc từ lớp DbContext
và chứa các thuộc tính DbSet<TEntity>
của các lớp thực thể Student
và Course
. Nó cũng ghi đè hai phương thức OnConfiguring
và OnModelCreating
.
Chúng ta phải tạo một thể hiện của SchoolContext
để kết nối với cơ sở dữ liệu và lưu hoặc truy xuất dữ liệu Student
hoặc Course
.
Phương thức OnConfiguring()
cho phép chúng ta lựa chọn và cấu hình nguồn dữ liệu được sử dụng với một Context sử dụng DbContextOptionsBuilder
. Tìm hiểu cách cấu hình một lớp DbContext tại đây .
Phương thức OnModelCreating()
cho phép chúng ta cấu hình mô hình sử dụng ModelBuilder
Fluent API.
Các phương thức của DbContext
Phương thức | Mô tả |
---|---|
Add |
Thêm một thực thể mới vào DbContext với trạng thái Added và bắt đầu theo dõi nó. Dữ liệu thực thể mới này sẽ được chèn vào cơ sở dữ liệu khi gọi SaveChanges().
|
AddAsync | Phương thức không đồng bộ để thêm một thực thể mới vào DbContext với trạng thái Added và bắt đầu theo dõi nó. Dữ liệu thực thể mới này sẽ được chèn vào cơ sở dữ liệu khi gọi SaveChangesAsync().
|
AddRange |
Thêm một tập các thực thể mới vào DbContext với trạng thái Added và bắt đầu theo dõi nó. Dữ liệu các thực thể mới này sẽ được chèn vào cơ sở dữ liệu khi gọi SaveChanges().
|
AddRangeAsync | Phương thức không đồng bộ để thêm tập các thực thể mới vào DbContext với trạng thái Added và bắt đầu theo dõi nó. Dữ liệu thực thể mới này sẽ được chèn vào cơ sở dữ liệu khi gọi SaveChangesAsync(). |
Attach |
Đính kèm một thực thể mới hoặc đã tồn tại vào DbContext với trạng thái Unchanged và bắt đầu theo dõi nó.
|
AttachRange |
Đính kèm một tập các thực thể mới hoặc đã tồn tại vào DbContext với trạng thái Unchanged và bắt đầu theo dõi nó.
|
Entry | Trả về một EntityEntry cho thực thể. Entry cung cấp quyền truy cập để thay đổi thông tin theo dõi và hoạt động cho thực thể.
|
Find | Tìm một thực thể với các giá trị khóa chính đã cho. |
FindAsync | Phương thức không đồng bộ để tìm một thực thể với các giá trị khóa chính đã cho. |
Remove | Thiết lập trạng thái Deleted cho thực thể được chỉ định sẽ xóa dữ liệu khi gọi SaveChanges(). |
RemoveRange | Thiết lập trạng thái Deleted cho một tập các thực thể sẽ xóa dữ liệu trong một lần gọi DB duy nhất khi gọi SaveChanges(). |
SaveChanges | Thực thi lệnh INSERT, UPDATE hoặc DELETE vào cơ sở dữ liệu cho các thực thể với trạng thái Added, Modified hoặc Deleted. |
SaveChangesAsync | Phương thức SaveChanges() không đồng bộ |
Set | Tạo một DbSet<TEntity> được sử dụng để truy vấn và lưu các thể hiện của TEntity. |
Update | Đính kèm thực thể bị ngắt kết nối với trạng thái Modified và bắt đầu theo dõi nó. Dữ liệu sẽ được lưu khi gọi SaveChagnes(). |
UpdateRange | Đính kèm một tập các thực thể bị ngắt kết nối với trạng thái Modified và bắt đầu theo dõi nó. Dữ liệu sẽ được lưu khi gọi SaveChagnes(). |
OnConfiguring | Ghi đè phương thức này để cấu hình cơ sở dữ liệu (và các tùy chọn khác) sẽ được sử dụng cho Context này. Phương thức này được gọi khi mỗi thể hiện của Context được tạo. |
OnModelCreating | Ghi đè phương thức này để cấu hình cho các thực thể trong các thuộc tính DbSet<TEntity> của lớp Context. |
Các thuộc tính của DbContext
Thuộc tính | Mô tả |
---|---|
ChangeTracker | Cung cấp truy cập vào thông tin và hoạt động cho các thể hiện của thực thể mà Context này đang theo dõi. |
Database | Cung cấp truy cập vào thông tin và hoạt động liên quan đến cơ sở dữ liệu cho Context này. |
Model | Trả về siêu dữ liệu của các thực thể, mối quan hệ giữa chúng và cách chúng ánh xạ tới cơ sở dữ liệu. |
Tạo ứng dụng EF Core đầu tiên
Ở hướng dẫn này, bạn sẽ tìm hiểu từng bước cách sử dụng Entity Framework Core theo cách tiếp cận Code First. Để minh họa, chúng tôi sẽ tạo một ứng dụng .NET Core Console bằng Visual Studio 2017 (hoặc mới hơn).
Ứng dụng .NET Core Console có thể được tạo bằng Visual Studio 2017 hoặc Giao diện dòng lệnh (CLI) cho .NET Core. Ở đây chúng tôi sẽ sử dụng Visual Studio 2017.
Để tạo ứng dụng .NET Core Console, hãy mở Visual Studio 2017 và chọn trên menu: File -> New -> Project.. Điều này sẽ mở cửa sổ bật lên New Project như hình ảnh bên dưới.
Trong cửa sổ New Project, mở rộng Installed -> Visual C# ở khung bên trái và chọn mẫu Console App (.NET Core) trong ngăn giữa.
Nhập tên dự án, vị trí đặt dự án và nhấp vào nút OK để tạo ứng dụng bảng điều khiển, như hình ảnh bên dưới.
Bây giờ, chúng ta cần cài đặt EF Core trong ứng dụng của mình bằng Package Manager Console. Chọn trên menu: Tools -> NuGet Package Manager -> Package Manager Console và thực hiện lệnh sau để cài đặt gói nhà cung cấp SQL Server:
PM> Install-Package Microsoft.EntityFrameworkCore.SqlServer
Tạo mô hình dữ liệu thực thể
Entity Framework cần có một mô hình dữ liệu thực thể để giao tiếp với cơ sở dữ liệu. Nó xây dựng một mô hình dựa trên các lớp thực thể của bạn bằng cách sử dụng cấu hình chú thích dữ liệu và Fluent API.
Mô hình EF bao gồm ba phần: mô hình khái niệm, mô hình lưu trữ và ánh xạ giữa mô hình khái niệm và mô hình lưu trữ.
Theo cách tiếp cận Code First, EF xây dựng mô hình khái niệm dựa trên các lớp thực thể của bạn, lớp Context và các cấu hình.
EF Core xây dựng mô hình lưu trữ và ánh xạ dựa trên trình cung cấp cơ sở dữ liệu bạn sử dụng. Ví dụ, mô hình lưu trữ của SQL Server sẽ khác với DB2.
EF sử dụng mô hình này cho các hoạt động CRUD (Create, Read, Update, Delete) cho cơ sở dữ liệu.
Tạo Migration trong EF Core
EF Core có các lệnh chuyển đổi (Migration) khác nhau để tạo hoặc cập nhật cơ sở dữ liệu dựa trên mô hình.
Tại thời điểm này chưa có cơ sở dữ liệu SchoolDB
. Vì vậy, chúng ta cần tạo cơ sở dữ liệu từ mô hình (thực thể và Context) bằng cách thêm chuyển đổi.
Chúng ta có thể thực thi lệnh chuyển đổi bằng cách sử dụng Package Manger Console hoặc dotnet CLI (giao diện dòng lệnh).
Trong Visual Studio, mở NuGet Package Manager Console từ Tools -> NuGet Package Manager -> Package Manager Console và nhập lệnh sau:
PM> add-migration CreateSchoolDB
Nếu bạn sử dụng dotnet CLI, hãy nhập lệnh sau.
> dotnet ef migrations add CreateSchoolDB
Xem chi tiết hướng dẫn từng bước tạo ứng dụng Entity Framework Core đầu tiên tại bài viết này.
Các quy ước trong Entity Framework Core
Các quy ước là các quy tắc mặc định bằng cách sử dụng Entity Framework để xây dựng một mô hình dựa trên các lớp thực thể của bạn.
Trong bài viết Ứng dụng EF Core đầu tiên, EF Core API tạo ra một lược đồ cơ sở dữ liệu dựa trên các lớp thực thể và lớp Context, không có bất kỳ cấu hình bổ sung nào vì các lớp thực thể đã tuân theo các quy ước.
Hãy xem các lớp thực thể và lớp Context sau để hiểu các quy ước mặc định.
public class Student
{
public int StudentId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime DateOfBirth { get; set; }
public byte[] Photo { get; set; }
public decimal Height { get; set; }
public float Weight { get; set; }
public int GradeId { get; set; }
public Grade Grade { get; set; }
}
public class Grade
{
public int Id { get; set; }
public string GradeName { get; set; }
public string Section { get; set; }
public IList<Student> Students { get; set; }
}
public class SchoolContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(@"Server=.SQLEXPRESS;Database=SchoolDB;Trusted_Connection=True;");
}
public DbSet<Student> Students { get; set; }
}
Chúng ta sẽ tìm hiểu các quy ước của EF Core và cách thức EF Core API tạo cơ sở dữ liệu cho các thực thể trên.
Lược đồ
Theo mặc định, EF Core sẽ tạo tất cả các đối tượng cơ sở dữ liệu trong lược đồ dbo.
Bảng
EF Core sẽ tạo các bảng cơ sở dữ liệu cho tất cả các thuộc tính DbSet<TEntity>
trong lớp Context có cùng tên với thuộc tính.
Nó cũng sẽ tạo các bảng cho các thực thể không phải là thuộc tính DbSet
nhưng có thể truy cập thông qua các thuộc tính tham chiếu trong các thực thể DbSet
khác.
Đối với ví dụ trên, EF Core sẽ tạo bảng Students
cho thuộc tính DbSet<Student>
trong lớp SchoolContext
và bảng Grade
cho thuộc tính Grade
trong lớp thực thể Student
, mặc dù lớp SchoolContext
không có thuộc tính DbSet<Grade>
.
Cột
Theo mặc định, EF Core sẽ tạo các cột cho tất cả các thuộc tính của một lớp thực thể có cùng tên với thuộc tính.
Nó sử dụng các thuộc tính tham chiếu và thuộc tính tập hợp trong việc xây dựng mối quan hệ giữa các bảng tương ứng trong cơ sở dữ liệu.
Kiểu dữ liệu cột
Kiểu dữ liệu cho các cột trong bảng cơ sở dữ liệu tùy thuộc vào cách nhà cung cấp cơ sở dữ liệu ánh xạ kiểu dữ liệu C# với kiểu dữ liệu của cơ sở dữ liệu đã chọn.
Bảng sau liệt kê ánh xạ giữa kiểu dữ liệu C# sang kiểu dữ liệu cột SQL Server.
Kiểu dữ liệu C# | Ánh xạ tới kiểu dữ liệu SQL Server |
---|---|
int | int |
string | nvarchar(Max) |
decimal | decimal(18,2) |
float | real |
byte[] | varbinary(Max) |
datetime | datetime |
bool | bit |
byte | tinyint |
short | smallint |
long | bigint |
double | float |
char | Không có ánh xạ |
sbyte | Không có ánh xạ (ném ra exception) |
object | Không có ánh xạ |
Cột Null
EF Core tạo các cột null cho tất cả các kiểu dữ liệu tham chiếu và các thuộc tính kiểu nguyên thủy nullable, ví dụ: string, Nullable<int>, decimal?.
Cột NotNull
EF Core tạo các cột NotNull trong cơ sở dữ liệu cho tất cả các thuộc tính khóa chính và các thuộc tính kiểu nguyên thủy, ví dụ: int, float, decimal, DateTime, v.v.
Khóa chính
EF Core sẽ tạo cột khóa chính cho thuộc tính có tên Id
hoặc <Entity Class Name>Id
(không phân biệt chữ hoa chữ thường).
Ví dụ, EF Core sẽ tạo một cột khóa chính trong bảng Students
nếu lớp Student
có một thuộc tính có tên id, ID, iD, Id, studentid, StudentId, STUDENTID hoặc sTUdentID.
Khóa ngoại
Theo quy ước khóa ngoại, EF Core API sẽ tạo một cột khóa ngoại cho mỗi thuộc tính điều hướng tham chiếu trong một thực thể với một trong các mẫu đặt tên sau.
<Reference Navigation Property Name>Id
<Reference Navigation Property Name><Principal Primary Key Property Name>
Trong ví dụ của chúng tôi (các thực thể Student
và Grade
), EF Core sẽ tạo một cột khóa ngoại GradeId
trong bảng Students
, như được mô tả trong hình dưới đây.
Bảng sau liệt kê các tên cột khóa ngoại cho các tên thuộc tính tham chiếu khác và các tên thuộc tính khóa chính.
Tên thuộc tính tham chiếu trong thực thể phụ thuộc | Tên thuộc tính khóa ngoại trong thực thể phụ thuộc | Tên thuộc tính khóa chính | Tên cột khóa ngoại trong DB |
---|---|---|---|
Grade | GradeId | GradeId | GradeId |
Grade | – | GradeId | GradeId |
Grade | – | Id | GradeId |
CurrentGrade | CurrentGradeId | GradeId | CurrentGradeId |
CurrentGrade | – | GradeId | CurrentGradeGradeId |
CurrentGrade | – | Id | CurrentGradeId |
CurrentGrade | GradeId | Id | GradeId |
Index
Theo mặc định, EF Core tạo clustered index trên các cột khóa chính và non-clustered index trên các cột khóa ngoại.
Quy ước về mối quan hệ một-nhiều trong EF Core
Ở phần này, bạn sẽ tìm hiểu về các quy ước mối quan hệ giữa hai lớp thực thể dẫn đến mối quan hệ một-nhiều giữa các bảng tương ứng trong cơ sở dữ liệu.
Entity Framework Core tuân theo quy ước tương tự như các quy ước mối quan hệ một-nhiều trong Entity Framework 6.x. Sự khác biệt duy nhất là EF Core tạo cột khóa ngoại có cùng tên với tên thuộc tính điều hướng chứ không phải là <NavigationPropertyName>_<PrimaryKeyPropertyName>
như trong Entity Framework.
Chúng ta sẽ xem các quy ước khác nhau trong EF Core tự động cấu hình mối quan hệ một-nhiều giữa các thực thể Student
và Grade
.
public class Student
{
public int StudentId { get; set; }
public string StudentName { get; set; }
}
public class Grade
{
public int GradeId { get; set; }
public string GradeName { get; set; }
public string Section { get; set; }
}
Sau khi áp dụng các quy ước cho mối quan hệ một-nhiều trong các thực thể ở trên, các bảng cơ sở dữ liệu cho các thực thể Student
và Grade
sẽ trông giống như hình bên dưới, trong đó bảng Students
có khóa ngoại GradeId
.
Quy ước về mối quan hệ một-một trong EF Core
Entity Framework Core đã giới thiệu các quy ước mặc định tự động định cấu hình mối quan hệ một-một giữa hai thực thể (EF 6.x hoặc trước đó không hỗ trợ các quy ước cho mối quan hệ một-một).
Trong EF Core, mối quan hệ một-một đòi hỏi một thuộc tính điều hướng tham chiếu ở cả hai bên. Sau đây các thực thể Student
và StudentAddress
tuân theo quy ước cho mối quan hệ một-một.
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public StudentAddress Address { get; set; }
}
public class StudentAddress
{
public int StudentAddressId { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Country { get; set; }
public int StudentId { get; set; }
public Student Student { get; set; }
}
Trong ví dụ trên, thực thể Student
có một thuộc tính điều hướng tham chiếu thuộc kiểu StudentAddress
và thực thể StudentAddress
có một thuộc tính khóa ngoại StudentId
và thuộc tính tham chiếu tương ứng của nó là Student
.
Điều này sẽ dẫn đến mối quan hệ một-một trong các bảng tương ứng Students
và StudentAddresses
trong cơ sở dữ liệu, như được hiển thị trong hình bên dưới.
EF Core tạo một unique index trên cột khóa ngoại StudentId
NotNull trong bảng StudentAddresses
, như được hiển thị ở trên.
Điều này đảm bảo rằng giá trị của cột khóa ngoại StudentId
phải là duy nhất trong bảng StudentAddress
, điều cần thiết cho mối quan hệ một-một.
Lưu ý: Ràng buộc duy nhất được hỗ trợ trong Entity Framework Core nhưng không phải trong EF 6 và đó là lý do tại sao EF Core có các quy ước cho mối quan hệ một-một còn EF 6.x thì không có.
Ngoài ra bạn cũng có thể sử dụng Fluent API để cấu hình mối quan hệ một-một nếu các thực thể không tuân theo các quy ước.
Bạn có thể xem hướng dẫn đầy đủ về các quy ước trong Entity Framework Core ở bài viết sau:
Cấu hình trong Entity Framework Core
Bạn đã tìm hiểu về các quy ước mặc định trong EF Core trong hướng dẫn trước. Đôi khi chúng ta muốn tùy chỉnh ánh xạ thực thể thành bảng cơ sở dữ liệu và không muốn tuân theo các quy ước mặc định.
EF Core cho phép chúng ta cấu hình các lớp thực thể để tùy chỉnh ánh xạ mô hình EF thành cơ sở dữ liệu. Mẫu lập trình này được gọi là Quy ước về Cấu hình.
Có hai cách để cấu hình các lớp thực thể trong EF Core (giống như trong EF 6).
- Cấu hình bằng cách sử dụng các attribute chú thích dữ liệu.
- Cấu hình bằng cách sử dụng Fluent API.
Attribute chú thích dữ liệu trong EF Core
Chú thích dữ liệu là một phương thức cấu hình dựa trên các attribute trong đó các attribute .NET khác nhau có thể được áp dụng cho các lớp thực thể và các thuộc tính để cấu hình mô hình.
Lưu ý: Bài viết sử dụng thuật ngữ gốc là attribute (thuộc tính) để tránh nhầm lẫn với các thuộc tính (property) của lớp.
Các attribute chú thích dữ liệu không chỉ dành riêng cho Entity Framework, mà chúng cũng được sử dụng trong ASP.NET MVC.
Đây là lý do tại sao các attribute này được đặt trong namespace riêng biệt là System.ComponentModel.DataAnnotations.
Ví dụ sau đây cho thấy cách các attribute chú thích dữ liệu có thể được áp dụng cho một lớp thực thể và các thuộc tính để ghi đè các quy ước mặc định.
[Table("StudentInfo")]
public class Student
{
public Student() { }
[Key]
public int SID { get; set; }
[Column("Name", TypeName="ntext")]
[MaxLength(20)]
public string StudentName { get; set; }
[NotMapped]
public int? Age { get; set; }
public int StdId { get; set; }
[ForeignKey("StdId")]
public virtual Standard Standard { get; set; }
}
Các attribute chú thích dữ liệu trong EF 6 và EF Core thì giống nhau. Do đó bạn có thể truy cập bài viết Attribute chú thích dữ liệu trong Entity Framework để biết thêm thông tin.
Fluent API trong EF Core
Một cách khác để cấu hình các lớp thực thể là bằng cách sử dụng Entity Framework Fluent API. EF Fluent API dựa trên mẫu thiết kế Fluent API (hay còn gọi là giao diện thông thạo) trong đó kết quả được tạo thành từ một chuỗi phương thức.
Trong Entity Framework Core, lớp ModelBuilder hoạt động như một Fluent API. Bằng cách sử dụng nó, chúng ta có thể cấu hình nhiều thứ khác nhau, vì nó cung cấp nhiều tùy chọn cấu hình hơn các attribute chú thích dữ liệu.
Entity Framework Core Fluent API cấu hình các khía cạnh sau của một mô hình:
- Cấu hình mô hình: Cấu hình mô hình EF để ánh xạ vào cơ sở dữ liệu. Cấu hình lượng đồ mặc định, các hàm DB, các thuộc tính và thực thể chú thích dữ liệu bổ sung được loại trừ khỏi ánh xạ.
- Cấu hình thực thể: Cấu hình thực thể cho bảng và ánh xạ mối quan hệ, ví dụ: khóa chính, khóa thay thể (AlternateKey), Index, tên bảng, các mối quan hệ như một-một, một-nhiều, nhiều-nhiều, v.v.
- Cấu hình thuộc tính: Cấu hình thuộc tính để ánh xạ cột, ví dụ tên cột, giá trị mặc định, nullable, khóa ngoại, kiểu dữ liệu, cột chống xung đột, v.v.
Bảng sau liệt kê các phương thức quan trọng cho từng loại cấu hình.
Phương thức | Mô tả |
---|---|
Cấu hình mô hình | |
HasDbFunction | Cấu hình chức năng cơ sở dữ liệu. |
HasDefaultSchema | Chỉ định lược đồ cơ sở dữ liệu mặc định. |
HasAnnotation | Thêm hoặc cập nhật các attribute chú thích dữ liệu trên thực thể. |
HasSequence | Cấu hình chuỗi cơ sở dữ liệu. |
Cấu hình thực thể | |
HasAlternateKey | Cấu hình khóa thay thế trong mô hình EF cho thực thể. |
HasIndex | Cấu hình thuộc tính Index cho kiểu thực thể. |
HasKey | Cấu hình thuộc tính khóa chính cho kiểu thực thể. |
HasMany | Cấu hình phần nhiều của mối quan hệ một-nhiều hoặc nhiều-nhiều. |
HasOne | Cấu hình phần một của mối quan hệ một-nhiều hoặc một-một. |
Ignore | Cấu hình lớp thực thể hoặc thuộc tính không được ánh xạ vào bảng hoặc cột trong cơ sở dữ liệu. |
OwnsOne | Cấu hình mối quan hệ trong đó thực thể đích được sở hữu bởi thực thể này. Giá trị khóa thực thể đích được truyền từ thực thể mà nó thuộc về. |
ToTable | Cấu hình tên bảng cho thực thể. |
Cấu hình thuộc tính | |
HasColumnName | Cấu hình tên cột tương ứng của một thuộc tính trong cơ sở dữ liệu. |
HasColumnType | Cấu hình kiểu dữ liệu của cột tương ứng của một thuộc tính trong cơ sở dữ liệu. |
HasComputedColumnSql | Cấu hình thuộc tính để ánh xạ tới cột được tính toán trong cơ sở dữ liệu. |
HasDefaultValue | Cấu hình giá trị mặc định cho cột mà thuộc tính ánh xạ. |
HasDefaultValueSql | Cấu hình biểu thức giá trị mặc định cho cột mà thuộc tính ánh xạ. |
HasField | Chỉ định trường sao lưu được sử dụng với thuộc tính. |
HasMaxLength | Cấu hình độ dài tối đa của dữ liệu có thể được lưu trữ trong một thuộc tính. |
IsConcurrencyToken | Cấu hình thuộc tính được sử dụng làm mã thông báo xung đột. |
IsRequired | Cấu hình thuộc tính bắt buộc nhập dữ liệu khi gọi phương thức SaveChanges. |
IsRowVersion | Cấu hình thuộc tính được sử dụng để phát hiện xung đột. |
IsUnicode | Cấu hình thuộc tính chuỗi có thể chứa các ký tự unicode hoặc không. |
ValueGeneratedNever | Cấu hình một thuộc tính không thể có giá trị được tạo tự động khi thực thể được lưu. |
ValueGeneratedOnAdd | Cấu hình rằng thuộc tính có giá trị được tạo tự động khi lưu thực thể mới. |
ValueGeneratedOnAddOrUpdate | Cấu hình rằng thuộc tính có giá trị được tạo tự động khi lưu thực thể mới hoặc cập nhật thực thể hiện có. |
ValueGeneratedOnUpdate | Cấu hình rằng thuộc tính có giá trị được tạo tự động khi cập nhật thực thể hiện có. |
Cấu hình Fluent API trong EF Core
Ghi đè phương thức OnModelCreating
và sử dụng tham số modelBuilder
kiểu ModelBuilder
để cấu hình các lớp thực thể như ví dụ bên dưới.
public class SchoolDBContext: DbContext
{
public DbSet<Student> Students { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
//Write Fluent API configurations here
//Property Configurations
modelBuilder.Entity<Student>()
.Property(s => s.StudentId)
.HasColumnName("Id")
.HasDefaultValue(0)
.IsRequired();
}
}
Trong ví dụ trên, thể hiện của ModelBuilder
được sử dụng để cấu hình một thuộc tính bằng cách gọi một chuỗi nhiều phương thức.
Nó cấu hình thuộc tính StudentId
của thực thể Student
:
StudentId
có tên làId
trong cơ sở dữ liệu bằng cách sử dụng phương thứcHasColumnName
StudentId
có giá trị mặc định là0
bằng cách sử dụng phương thứcHasDefaultValue
StudentId
cho phép nullable bằng phương thứcIsRequired
Các cấu hình trên được thực hiện trong một câu lệnh thay vì nhiều câu lệnh. Điều này làm tăng khả năng đọc và cũng mất ít thời gian hơn để viết so với nhiều câu lệnh, như được trình bày bên dưới.
//Fluent API method chained calls
modelBuilder.Entity<Student>()
.Property(s => s.StudentId)
.HasColumnName("Id")
.HasDefaultValue(0)
.IsRequired();
//Separate method calls
modelBuilder.Entity<Student>().Property(s => s.StudentId).HasColumnName("Id");
modelBuilder.Entity<Student>().Property(s => s.StudentId).HasDefaultValue(0);
modelBuilder.Entity<Student>().Property(s => s.StudentId).IsRequired();
Lưu ý: Cấu hình Fluent API có quyền ưu tiên cao hơn các attribute chú thích dữ liệu.
Bạn có thể xem hướng dẫn đầy đủ về cấu hình trong Entity Framework Core tại đây:
Truy vấn trong Entity Framework Core
Truy vấn trong Entity Framework Core vẫn giống như truy vấn trong Entity Framework 6.x, với các truy vấn SQL được tối ưu hóa hơn và khả năng đưa các phương thức C# / VB.NET vào các truy vấn LINQ-to-Entities.
Ở phần này, bạn sẽ tìm hiểu các tính năng mới của truy vấn được giới thiệu trong Entity Framework Core.
Phương thức C# / VB.NET trong truy vấn
EF Core có một tính năng mới trong LINQ-to-Entities nơi chúng ta có thể thêm các phương thức C# hoặc VB.NET trong truy vấn. Điều này là không thể trong EF 6.
private static void Main(string[] args)
{
var context = new SchoolContext();
var studentsWithSameName = context.Students
.Where(s => s.FirstName == GetName())
.ToList();
}
public static string GetName()
{
return "Bill";
}
Eager Loading trong EF Core
Eager Loading là gì?
Eager Loading là quá trình trong đó một truy vấn cho một kiểu thực thể cũng tải các thực thể liên quan như một phần của truy vấn, do đó chúng ta không cần phải thực hiện một truy vấn riêng cho các thực thể liên quan.
Entity Framework Core hỗ trợ Eager Loading các thực thể liên quan, giống như EF 6, sử dụng phương thức mở rộng Include()
và truy vấn tạo kết quả đầu ra.
Ngoài ra, nó cũng cung cấp phương thức mở rộng ThenInclude()
để tải nhiều cấp độ của các thực thể liên quan. (EF 6 không hỗ trợ phương thức ThenInclude()
)
Phương thức Include trong EF Core
Không giống như EF 6, chúng ta có thể chỉ định biểu thức lambda làm tham số trong phương thức Include()
để chỉ định thuộc tính điều hướng như dưới đây.
var context = new SchoolContext();
var studentWithGrade = context.Students
.Where(s => s.FirstName == "Bill")
.Include(s => s.Grade)
.FirstOrDefault();
Phương thức ThenInclude trong EF Core
EF Core đã giới thiệu phương thức mở rộng ThenInclude()
mới để tải nhiều cấp độ của các thực thể liên quan. Hãy xem xét ví dụ sau:
var context = new SchoolContext();
var student = context.Students.Where(s => s.FirstName == "Bill")
.Include(s => s.Grade)
.ThenInclude(g => g.Teachers)
.FirstOrDefault();
Truy vấn tạo kết quả đầu ra
Chúng tôi cũng có thể tải nhiều thực thể liên quan bằng cách sử dụng truy vấn tạo kết quả đầu ra thay vì sử dụng phương thức Include()
hoặc ThenInclude()
.
Ví dụ sau đây cho thấy các truy vấn tạo kết quả đầu ra để tải các thực thể Student
, Grade
và Teacher
.
var context = new SchoolContext();
var stud = context.Students.Where(s => s.FirstName == "Bill")
.Select(s => new
{
Student = s,
Grade = s.Grade,
GradeTeachers = s.Grade.Teachers
})
.FirstOrDefault();
Lazy loading trong EF Core
Lazy loading trì hoãn việc tải các dữ liệu liên quan, cho đến khi bạn yêu cầu cụ thể. Lazy loading đối lập hoàn toàn với Eager loading.
Lazy loading được giới thiệu trong EF Core 2.1 như một tính năng tùy chọn bổ sung.
Lazy loading có thể được kích hoạt theo hai cách:
- Sử dụng Proxies
- Sử dụng interface
ILazyLoader
Explicit Loading trong EF Core
Ở phần này bạn sẽ tìm hiểu làm thế nào để tải các thực thể liên quan trong một biểu đồ thực thể rõ ràng.
Sử dụng phương thức Load()
để tải các thực thể liên quan một cách rõ ràng. Hãy xem xét ví dụ sau.
using (var context = new SchoolContext())
{
var student = context.Students
.Where(s => s.FirstName == "Bill")
.FirstOrDefault<Student>();
// loads StudentAddress
context.Entry(student).Reference(s => s.StudentAddress).Load();
// loads Courses collection
context.Entry(student).Collection(s => s.StudentCourses).Load();
}
Bạn có thể xem hướng dẫn đầy đủ về truy vấn trong Entity Framework Core ở bài viết này:
Kịch bản lưu dữ liệu trong Entity Framework Core
Entity Framework Core cung cấp các cách khác nhau để thêm, cập nhật hoặc xóa dữ liệu trong cơ sở dữ liệu. Một thực thể chứa dữ liệu trong thuộc tính của nó sẽ được thêm hoặc cập nhật hoặc xóa dựa trên trạng thái EntityState
của nó.
Có hai kịch bản để lưu dữ liệu thực thể: được kết nối và ngắt kết nối. Trong kịch bản được kết nối, cùng một thể hiện DbContext
được sử dụng trong việc truy xuất và lưu các thực thể, trong khi điều này khác với kịch bản ngắt kết nối.
Lưu dữ liệu trong kịch bản được kết nối trong EF Core
Hình dưới đây minh họa các thao tác CUD (Create, Update, Delete) trong kịch bản được kết nối.
Theo hình trên, Entity Framework xây dựng và thực thi các câu lệnh INSERT, UPDATE hoặc DELETE cho các thực thể có trạng thái EntityState
là Added, Modified hoặc Deleted khi phương thức DbContext.SaveChanges()
được gọi.
Trong kịch bản được kết nối, một thể hiện DbContext
theo dõi tất cả các thực thể và do đó, nó sẽ tự động thiết lập một trạng thái EntityState
phù hợp cho mỗi thực thể bất cứ khi nào một thực thể được tạo, sửa đổi hoặc xóa.
Lưu dữ liệu trong kịch bản ngắt kết nối trong EF Core
Lưu dữ liệu trong kịch bản ngắt kết nối hơi khác một chút so với kịch bản được kết nối.
Trong kịch bản bị ngắt kết nối, DbContext
không biết các thực thể bị ngắt kết nối vì các thực thể đã được thêm hoặc sửa đổi ngoài phạm vi của thể hiện DbContext
hiện tại.
Vì vậy, bạn cần đính kèm (attach) các thực thể bị ngắt kết nối vào một Context với trạng thái EntityState
phù hợp để thực hiện các thao tác CUD (Create, Update, Delete) vào cơ sở dữ liệu.
Hình dưới đây minh họa các thao tác CUD trong kịch bản ngắt kết nối:
Theo hình trên, các thực thể bị ngắt kết nối (các thực thể không được theo dõi bởi DbContext
) cần phải được đính kèm vào DbContext
với trạng thái EntityState
phù hợp.
Ví dụ: Trạng thái Added cho các thực thể mới, trạng thái Modified cho các thực thể đã chỉnh sửa và trạng thái Deleted cho các thực thể bị xóa, điều này sẽ thực thi các lệnh INSERT, UPDATE hoặc DELETE trong cơ sở dữ liệu khi phương thức SaveChanges()
được gọi.
Bạn có thể xem hướng dẫn đầy đủ về kịch bản lưu dữ liệu trong Entity Framework Core ở bài viết này:
Còn tiếp