DbContext API, tổng quan về xử lý dữ liệu với EntityFramework

    0

    Trong các bài học ở giai đoạn trước bạn đã tập trung vào xây dựng mô hình khái niệm (conceptual model). Nhiệm vụ của nó là xây dựng domain class và ánh xạ nó với cơ sở dữ liệu.

    Mặc dù đóng vai trò nền tảng cho việc tương tác với dữ liệu, tự bản thân mô hình khái niệm không tương tác với dữ liệu. Để làm việc với dữ liệu (như truy vấn, thêm, sửa, xóa, v.v.), bạn cần một loạt kiến thức và kỹ năng khác.

    Từ bài học này chúng ta sẽ chuyển trọng tâm sang làm việc với dữ liệu. Các nội dung của chương này tập trung vào:

    • (1) xử lý dữ liệu (Create, Update, Delete – CUD) với change tracking;
    • (2) truy vấn dữ liệu với LINQ to Entities;
    • (3) các vấn đề đặc biệt trong truy vấn dữ liệu (lazy loading, eager loading);
    • (4) xử lý bất đồng bộ (asynchronous) và tương tranh (concurrency).

    Tất cả các thao tác xử lý trên dữ liệu của Entity Framework đều dựa trên một nhóm tính năng được gọi chung là DbContext API, được xây dựng trong nhóm class DbContext, DbSet, và DbQuery.

    Trong bài học này chúng ta sẽ xem xét tổng quan về DbContext API và các class liên quan. Các bài học tiếp theo sẽ đi vào từng vấn đề cụ thể của xử lý dữ liệu sử dụng DbContext API.

    DbContext API là gì?

    Trước hết nhắc lại một chút về lịch sử. Ở những phiên bản đầu tiên (trước 4.1), ObjectContext, ObjectSet và ObjectQuery là những class trọng tâm khi làm việc với dữ liệu trong Entity Framework.

    Tuy nhiên, nhóm class này bộc lộ nhiều tính năng không cần thiết gây khó khăn trong quá trình làm việc với Entity Framework. Ngoài ra, một số tính năng thường được sử dụng nhưng lại khó học và khó dùng.

    Vì vậy, bắt đầu từ Entity Framework 4.1, nhóm phát triển đã tạo ra nhóm class mới với mục đích che bớt những gì không cần thiết của ObjectContext, đơn giản hóa việc sử dụng những tính năng thông dụng nhất, đồng thời bổ sung một số tính năng mới.

    Nhóm class mới này chính là DbContext, DbSet và DbQuery. Các tính năng mà nhóm class này cung cấp cho người lập trình được gọi là DbContext API, lấy theo tên của class trọng tâm của nhóm.

    Một cách tóm lược:

    • Lớp DbContext biểu diễn một phiên làm việc với cơ sở dữ liệu, cung cấp khả năng truy vấn, theo dõi object và lưu dữ liệu. Lớp này bộc lộ một phần tính năng cũng như đơn giản hóa cách sử dụng một số tính năng thông dụng của ObjectContext.
    • Lớp DbSet cung cấp các phép toán hoạt động trên các kiểu entity (Add, Remove, Attach, v.v.). DbSet kế thừa từ DbQuery để cung cấp thêm khả năng viết truy vấn trên tập hợp entity. DbSset bộc lộ và dơn giản hóa một số tính năng thông dụng của ObjectSet.
    • Lớp DbQuery cung cấp khả năng viết truy vấn trên tập hợp Entity. Đây là lớp cha của DbSet, và các tính năng của nó đã bộc lộ qua DbSet. Do đó, bạn không cần làm việc trực tiếp với DbQuery.

    Ngoài ra, DbContext API cung cấp thêm một số tính năng quan trọng khác, bao gồm:

    • Change Tracker API: cho phép truy xuất tới các thông tin và phép toán của hệ thống theo dõi object do context quản lý. Ví dụ, khi object thay đổi giá trị, bạn có thể truy xuất giá trị gốc của nó hoặc giá trị hiện tại. Đây là tính năng đơn giản hóa của ObjectContext.ObjectStateManager.
    • Validation API: cung cấp khả năng kiểm tra dữ liệu tự động. Validation API khai thác tính năng kiểm tra dữ liệu của .NET 4. Đây là một tính năng riêng của DbContext API.
    • Code First Model Building: có khả năng đọc các class và file cấu hình để tạo model class, metadata và cơ sở dữ liệu. Đây cũng là tính năng riêng của DbContext API.

    Khi bạn đã hình dung được DbContext API là gì, giờ là lúc chúng ta xem xét kỹ hơn lớp DbContext.

    Lớp DbContext trong Entity Framework

    Bạn đã tiếp xúc với class DbContext (System.Data.Entity.DbContext) ngay từ bài học đầu tiên về Entity Framework code-first.
    Đây là class quan trọng nhất trong Entity Framework API, là class trung tâm của DbContext API và phối hợp hoạt động của DbSet (và DbQuery).

    Các class kế thừa từ DbContext được gọi chung là context class. Một object của context class khi chương trình hoạt động cũng thường được gọi tắt là context.

    Vai trò của DbContext

    Khi chương trình hoạt động, context biểu diễn một phiên làm việc với cơ sở dữ liệu. Chi tiết hơn, context chịu trách nhiệm cho các chức năng cụ thể sau:

    • Truy vấn dữ liệu (querying): chuyển đổi truy vấn LINQ to Entities thành truy vấn SQL và gửi tới cơ sở dữ liệu.
    • Theo dõi sự thay đổi của các object (change tracking): theo dõi sự thay đổi của các entity trong quá trình hoạt động của chương trình, như entity nào được tạo mới, entity nào bị thay đổi, entity nào bị xóa khỏi danh sách. Việc theo dõi này giúp DbContext chỉ sinh ra các truy vấn SQL cần thiết tương ứng cho mỗi sự thay đổi.
    • Lưu dữ liệu (persistence): gửi các truy vấn Insert, Update và Delete tới database. Các truy vấn này được sinh ra dựa trên sự theo dõi các object.
    • Quản lý các quan hệ (relationship management);
    • Tạo và quản lý bộ đệm (caching): lưu tạm các entity lấy được từ cơ sở dữ liệu để hạn chế truy vấn và tăng hiệu suất.
    • Xử lý giao dịch (transaction);
    • Chuyển đổi dữ liệu bảng sang object (object meterialization): dữ liệu thô lấy được từ cơ sở dữ liệu cần chuyển đổi thành object tương ứng của entity class để chương trình có thể sử dụng.

    Phương thức và thuộc tính của DbContext

    Dưới đây là những phương thức và thuộc tính của DbContext. Một số trong đó bạn đã từng tiếp xúc trong các bài học trước.

    Lưu ý rằng, mục này chỉ mang tính chất giới thiệu. Bạn không cần học thuộc hay hiểu hết. Chúng ta sẽ (và đã) sử dụng các phương thức và thuộc tính này trong các bài học tương ứng.

    Phương thức

    Nhiệm vụ

    Entry

    Lấy thông tin của entity để truy xuất các thông tin liên quan đến sự thay đổi của entity, hoặc thực hiện các thao tác đối với entity.

    SaveChanges

    Tạo và thực thi các truy vấn INSERT, UPDATE và DELETE đối với các entity có trạng thái tương ứng (Added, Modified, Deleted).

    SaveChangesAsync

    Phiên bản bất đồng bộ của SaveChanges()

    Set

    Tạo object của DbSet<Tentity> dùng để truy vấn và lưu các biến của Tentity.

    OnModelCreating

    Phương thức virtual cho phép bạn ghi đè trong lớp context để thực hiện cấu hình cho cơ sở dữ liệu sử dụng fluent API.

    Property

    Nhiệm vụ

    ChangeTracker

    Property này cho phép truy xuất tới Change Tracker API, tức là truy xuất tới thông tin và hoạt động của các entity đang được context này theo dõi.

    Configuration

    Truy xuất tới các thông tin cấu hình.

    Database

    Truy xuất tới các thông tin và hoạt động của cơ sở dữ liệu.

    Một số đặc điểm quan trọng khi sử dụng DbContext

    DbContext thực thi hai mô hình quan trọng: Unit of Work và Repository. Vì vậy, trong một dự án, bạn không cần tự mình xây dựng hai mô hình trên nữa.

    Bạn nên tạo ra hai project (Class Library): (1) project dành cho các domain class; (2) project chứa context class. Project thứ hai tham chiếu tới project thứ nhất, đồng thời cũng tham chiếu tới các thư viện của Entity Framework.

    Do context chịu trách nhiệm quản lý kết nối tới cơ sở dữ liệu, bạn cần giải phóng kết nối nếu không cần sử dụng tới nữa. Do DbContext thực thi giao diện IDisposable, bạn nên gọi Dispose khi không tiếp tục sử dụng tới object context.

    Một cách khác đơn giản hơn là đặt khai báo biến context vào cấu trúc using mà bạn đã gặp:

    using(var context = new Context())
    {
       ...
    }

    Cấu trúc using đảm bảo sẽ tự động gọi Dispose khi kết thúc code block.

    Lớp DbSet

    DbSet là một tập hợp các entity object và có thể thực hiện các lệnh tạo mới / đọc / cập nhật / xóa bỏ các entity chứa trong đó.

    Dưới đây là những phương thức quan trọng của lớp DbSet:

    Phương thức

    Nhiệm vụ

    Add

    Thêm entity object mới vào danh sách.

    AsNoTracking<Entity>

    Đây là phương thức kế thừa từ DbQuery, trả về một danh sách entity nhưng các entity trong đó không được cached (và cũng không được track) bởi context. Sử dụng phương thức này nếu cần các entity chỉ đọc để tăng hiệu suất truy vấn.

    Attach(Entity)

    Gắn (attach) một entity đã có vào tập hợp. Nhiệm vụ của Attach đơn giản là báo cho Entity Framework biết rằng đây là một entity đã có sẵn, thay vì phải tải nó từ CSDL.

    Create

    Tạo một entity mới nhưng không được thêm vào danh sách quản lý của DbSet.

    Find(int)

    Tìm một entity đang được theo dõi trong context.

    Include

    Yêu cầu tải thêm các entity có quan hệ (1-n, n-n, 1-1).

    Remove

    Đánh dấu xóa cho entity.

    SqlQuery

    Chạy truy vấn SQL.

    Các phương thức tác động tới dữ liệu của DbSet chỉ có tác dụng với các entity (object) chứa trong nó, chứ không tác động ngay đến bảng dữ liệu. Vấn đề nằm ở chỗ, DbSet khi phối hợp với DbContext thực hiện các thao tác xử lý dữ liệu theo cách hơi khác.

    Mỗi object lưu trong DbSet sẽ đồng thời được theo dõi bởi DbContext. Để theo dõi, mỗi object được gắn một trong những trạng thái (EntityState enum): Unchanged (không thay đổi gì), Modified (cập nhật), Deleted (xóa), Added (thêm mới). Việc gọi các phương thức như Add, Remove hoặc khi thay đổi giá trị của entity sẽ làm biến đổi trạng thái của nó.

    Khi gọi SaveChanges, DbContext sẽ căn cứ vào trạng thái trên để tạo truy vấn phù hợp. Do đó, các kết quả chỉ được lưu trở lại cơ sở dữ liệu khi gọi SaveChanges của context.

    Kết luận

    Bài học này giới thiệu tổng quan về DbContext API – nhóm tính năng truy xuất và xử lý dữ liệu của Entity Framework. Đây là bài học tiền đề để bạn tiếp tục đi sâu vào từng khía cạnh của xử lý dữ liệu với Entity Framework.

    Nếu có thắc mắc hoặc cần trao đổi thêm, mời bạn viết trong phần Bình luận ở cuối trang. Nếu cần trao đổi riêng, hãy gửi email hoặc nhắn tin qua form liên hệ. Nếu bài viết hữu ích với bạn, hãy giúp chúng tôi chia sẻ tới mọi người. Cảm ơn bạn!

    Bình luận

    avatar
      Đăng ký theo dõi  
    Thông báo về