Asynchronous trong Entity Framework

Việc thực thi không đồng bộ (asynchronous) đã được giới thiệu trong .NET 4.5 và nó rất hữu ích trong Entity Framework (EF).

Entity Framework (EF) 6 cho phép chúng ta thực thi một truy vấn và câu lệnh không đồng bộ bằng cách sử dụng một thể hiện của DbContext.

Trước tiên, hãy xem cách thực thi các truy vấn không đồng bộ, sau đó chúng ta sẽ thấy gọi phương thức context.SaveChanges không đồng bộ.

Truy vấn không đồng bộ

Sau đây là một ví dụ về phương thức async thực thi truy vấn LINQ-to-Entities không đồng bộ và trả về kết quả.

private async Task<Student> GetStudentAsync()
{
    Student student = null;

    using (var context = new SchoolDBEntities())
    {
        Console.WriteLine("Start GetStudent...");
              
        student = await context.Students.Where(s => s.StudentID == 1)
                                        .FirstOrDefaultAsync<Student>();
            
        Console.WriteLine("Finished GetStudent...");
    }

    return student;
}

Như bạn có thể thấy trong đoạn mã trên, phương thức GetStudentAsync() được khai báo bằng từ khóa async, điều này làm cho nó trở thành một phương thức không đồng bộ.

Kiểu trả về của phương thức không đồng bộ phải là Task<T>, Task, void. Phương thức GetStudentAsync() trả về một đối tượng của thực thể Student, vì vậy kiểu trả về phải có kiểu Task<Student>.

Ngoài ra, truy vấn LINQ được khai báo bằng từ khóa await. Điều này sẽ giải phóng luồng gọi để thực thi mã khác cho đến khi nó thực hiện truy vấn và trả về kết quả.

Chúng tôi đã sử dụng phương thức mở rộng không đồng bộ FirstOrDefaultAsync để trả về kết quả.

Bạn cũng có thể sử dụng các phương thức không đồng bộ khác như SingleOrDefaultAsync(), ToListAsync() v.v.  một cách thích hợp.

Lưu thực thể không đồng bộ

Entity Framework API cung cấp phương thức không đồng bộ SaveChangesAsync() để lưu các thực thể vào cơ sở dữ liệu không đồng bộ.

Phương thức SaveStudentAsync sau đây lưu thực thể Student vào cơ sở dữ liệu không đồng bộ.

private async Task SaveStudentAsync(Student editedStudent)
{
    using (var context = new SchoolDBEntities())
    {
        context.Entry(editedStudent).State = EntityState.Modified;
                
        Console.WriteLine("Start SaveStudent...");
                
        int x = await (context.SaveChangesAsync());
                
        Console.WriteLine("Finished SaveStudent...");
    }
}

Nhận kết quả truy vấn không đồng bộ

Ví dụ sau đây cho thấy việc thực hiện truy vấn không đồng bộ, nhận kết quả và lưu thực thể đã sửa đổi.

public void QueryAndSaveAsync()
{
    var query = GetStudent();
            
    Console.WriteLine("Do something else here till we get the query result..");

    query.Wait();

    var student = query.Result;
	
    student.FirstName = "Steve";
            
    var numOfSavedStudent = SaveStudent(student);
            
    Console.WriteLine("Do something else here till we save a student.." );

    studentSave.Wait();

    Console.WriteLine("Saved Entities: {0}", numOfSavedStudent.Result);
}

Đây là kết quả khi biên dịch và chạy chương trình:

Start GetStudent...
Do something else here till we get the query result..
Finished GetStudent...
Start SaveStudent...
Do something else here till we save a student..
Finished SaveStudent...
Saved Entities: 1

Trong ví dụ trên, phương thức không đồng bộ GetStudentAsync() được gọi và nó lưu tham chiếu trong biến query.

Điều này sẽ bắt đầu thực thi phương thức GetStudentAsync(), nhưng giải phóng luồng gọi, để nó có thể thực thi các câu lệnh tiếp theo trong phương thức QueryAndSaveAsync.

Phương thức query.Wait() sẽ chờ thực thi cho đến khi  phương pháp không đồng bộ hoàn thành. Khi nó hoàn thành, chúng ta có thể nhận được kết quả bằng cách sử dụng biến query.Result.

Theo cùng một cách, phương thức lưu không đồng bộ được gọi và nhận kết quả.

Ngoài ra chúng ta có thể viết lại phương thức QueryAndSaveAsync theo cách ngắn gọn như sau:

public async Task QueryAndSaveAsync()
{
    Console.WriteLine("Do something else here till we get the query result..");

    var student = await GetStudentAsync();            
    student.FirstName = "Steve";
            
    Console.WriteLine("Do something else here till we save a student.." );

    var numOfSavedStudent = await SaveStudentAsync(student);
            
    Console.WriteLine("Saved Entities: {0}", numOfSavedStudent);
}
Tip: những phương thức không đồng bộ nên có tên kết thúc bằng Async để phân biệt với những phương thức đồng bộ.


Bài viết liên quan:

2 kịch bản lưu dữ liệu trong Entity Framework Core là kịch bản được kết nối và kịch bản ngắt kết nối.

Tạo ứng dụng .NET Core Console đầu tiên và cấu hình sử dụng Entity Framework Core.

Truy vấn trong Entity Framework Core có gì mới? Truy vấn trong EF Core khác EF ở những điểm nào.