Vòng đời trong Entity Framework

Vòng đời

Thời gian tồn tại của một Context bắt đầu khi thể hiện của nó được khởi tạo và kết thúc khi thể hiện đó được hủy hoặc được thu gom rác.

  • Vòng đời của Context là một yếu tố rất quan trọng cần được xác định khi chúng ta sử dụng ORM.
  • Context hoạt động giống như một bộ đệm thực thể, có nghĩa là nó chứa các tham chiếu đến tất cả các thực thể được tải. Điều này khiến nó có thể tăng rất nhanh về mức tiêu thụ bộ nhớ và nó cũng có thể gây rò rỉ bộ nhớ.
  • Trong sơ đồ bên dưới, bạn có thể thấy luồng công việc từ ứng dụng đến cơ sở dữ liệu thông qua Context và ngược lại có lưu lượng rất cao.
Luồng dữ liệu

Vòng đời thực thể

Vòng đời thực thể mô tả quá trình thực thể được tạo, thêm, sửa đổi, xóa, v.v. Các thực thể có nhiều trạng thái trong suốt vòng đời của nó.

Trước khi xem cách lấy lại trạng thái thực thể, chúng ta hãy xem trạng thái thực thể là gì. Trạng thái là một enum của kiểu System.Data.EntityState khai báo các giá trị sau:

  • Added: Thực thể được đánh dấu là đã thêm.
  • Deleted: Thực thể được đánh dấu là đã xóa.
  • Modified: Thực thể đã được sửa đổi.
  • Unchanged: Thực thể chưa được sửa đổi.
  • Detached: Thực thể không được theo dõi.

Thay đổi trạng thái trong vòng đời thực thể

Đôi khi trạng thái của các thực thể được thiết lập tự động theo Context, nhưng nó cũng có thể được nhà phát triển sửa đổi bằng tay.

Mặc dù tất cả sự kết hợp của chuyển từ trạng thái này sang trạng thái khác là có thể, nhưng một số trong số chúng là vô nghĩa. Ví dụ: chuyển thực thể có trạng thái Added vào trạng thái Deleted hoặc ngược lại.

Hãy cùng thảo luận về các trạng thái khác nhau của vòng đời thực thể.

Trạng thái Unchanged

  • Khi một thực thể không được thay đổi, nó bị ràng buộc với Context nhưng nó đã không được sửa đổi.
  • Theo mặc định, một thực thể được lấy từ cơ sở dữ liệu ở trạng thái này.
  • Khi một thực thể được gắn vào Context (sử dụng phương thức Attach), nó cũng ở trạng thái Unchanged.
  • Context không thể theo dõi các thay đổi của các đối tượng mà nó không tham chiếu, vì vậy khi chúng được đính kèm, nó cho rằng chúng không bị thay đổi.

Trạng thái Detached

  • Detached là trạng thái mặc định của thực thể mới được tạo vì Context không thể theo dõi việc tạo bất kỳ đối tượng nào trong mã của bạn.
  • Điều này đúng ngay cả khi bạn khởi tạo thực thể bên trong một khối using của Context.
  • Detached thậm chí là trạng thái của các thực thể được lấy từ cơ sở dữ liệu khi theo dõi bị vô hiệu hóa.
  • Khi một thực thể được tách ra, nó không bị ràng buộc với Context, vì vậy trạng thái của nó không được theo dõi.
  • Nó có thể được xử lý, sửa đổi, sử dụng kết hợp với các lớp khác hoặc được sử dụng theo bất kỳ cách nào khác mà bạn có thể cần.
  • Bởi vì không có Context theo dõi nó, nó không có ý nghĩa gì với Entity Framework.

Trạng thái Added

  • Khi một thực thể ở trạng thái Added, bạn có một vài tùy chọn. Trong thực tế, bạn chỉ có thể tách nó ra khỏi Context.
  • Đương nhiên, ngay cả khi bạn sửa đổi một số thuộc tính, trạng thái vẫn là Added, bởi vì việc chuyển nó sang Modified, Unchanged hoặc Deleted không có ý nghĩa vì ID của thực thể mới chưa có trong cơ sở dữ liệu.
  • Đây là một thực thể mới và không có sự tương ứng với một bản ghi trong cơ sở dữ liệu.
  • Đây cũng là điều kiện cơ bản để có trạng thái Added (nhưng quy tắc này không được thực thi bởi Context).
Trạng thái Added trong Entity Framework

Trạng thái Modified

  • Khi một thực thể được sửa đổi, điều đó có nghĩa là nó đang ở trạng thái Unchanged và sau đó một số thuộc tính đã được thay đổi.
  • Sau khi một thực thể ở trạng thái Modified, nó có thể chuyển sang trạng thái Detached hoặc Deleted, nhưng nó không thể quay trở lại trạng thái Unchanged ngay cả khi bạn khôi phục thủ công các giá trị ban đầu.
  • Nó thậm chí không thể được thay đổi thành Added, trừ khi bạn tách ra và thêm thực thể vào Context, bởi vì một bản ghi có ID này đã tồn tại trong cơ sở dữ liệu và bạn sẽ có một ngoại lệ lúc thực thi khi duy trì nó.

Trạng thái Deleted

  • Một thực thể có trạng thái Deleted khi phương thức DeleteObject được sử dụng.
  • Đây là trạng thái hạn chế nhất, bởi vì bạn sẽ không thể thay đổi từ trạng thái này sang bất kỳ trạng thái nào khác ngoài trạng thái Detached.

Sử dụng câu lệnh using nếu bạn muốn tất cả các tài nguyên mà Context sử dụng được tự động giải phóng khi thoát khỏi khối lệnh.

Khi bạn sử dụng câu lệnh using thì trình biên dịch sẽ tự động tạo một khối try/finally, các lệnh hủy và giải phóng bộ nhớ sẽ được gọi trong khối finally.

using (var context = new UniContext()) 
{
   var student = new Student 
   {
      LastName = "Khan", 
      FirstMidName = "Ali", 
      EnrollmentDate = DateTime.Parse("2020-04-01")
   };

   context.Students.Add(student);
   context.SaveChanges();
}

Khi bạn muốn sử dụng Context chạy lâu dài, hãy xem xét những vấn đề sau đây:

  • Khi bạn tải nhiều đối tượng và tham chiếu của chúng vào bộ nhớ, mức tiêu thụ bộ nhớ của Context có thể tăng nhanh. Điều này có thể gây ra vấn đề hiệu suất.
  • Hãy nhớ hủy và giải phóng bộ nhớ cho Context khi nó không còn cần thiết.
  • Nếu một ngoại lệ khiến Context ở trạng thái không thể phục hồi, toàn bộ ứng dụng có thể kết thúc.
  • Nguy cơ xảy ra các vấn đề liên quan đến tranh chấp tăng lên khi khoảng cách giữa thời điểm dữ liệu được truy vấn và cập nhật tăng lên.
  • Khi làm việc với các ứng dụng Web, hãy sử dụng một thể hiện Context cho mỗi yêu cầu.
  • Khi làm việc với Windows Presentation Foundation (WPF) hoặc Windows Forms, hãy sử dụng một thể hiện ngữ cảnh cho mỗi Form. Điều này cho phép bạn sử dụng chức năng theo dõi thay đổi mà Context cung cấp.

Quy tắc ngón tay cái

Ứng dụng web

  • Đối với các ứng dụng web, Context nên được sử dụng trong phạm vi một yêu cầu. Khi yêu cầu kết thúc chúng ta sẽ hủy và giải phóng bộ nhớ cho Context.
  • Trong các ứng dụng web, chúng ta xử lý các yêu cầu rất ngắn nhưng vì có rất nhiều yêu cầu như vậy tới máy chủ do đó thể hiện của Context chỉ nên tồn tại trong phạm vi của một yêu cầu.
  • Nếu  ứng dụng Web của bạn sử dụng IoC container thì nên thiết lập vòng đời cho Context là Scoped để sử dụng cùng một thể hiện của Context trong cùng một yêu cầu.

Ứng dụng máy tính để bàn

  • Đối với ứng dụng máy tính để bàn, như Win Forms / WPF, v.v. Context được sử dụng cho mỗi Form / Dialog / Page.
  • Do đó chúng tôi không muốn có Context dưới dạng singleton cho ứng dụng của mình, chúng tôi sẽ hủy và giải phóng bộ nhớ của Context khi chúng tôi chuyển từ Form này sang Form khác.
  • Theo cách này, chúng ta sẽ đạt được rất nhiều lợi ích của Context và sẽ không phải chịu những tác động của việc sử dụng Context chạy lâu dài.


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.