Hướng Dẫn Lưu Dữ Liệu Liên Kết Trong FreeSql Repository

Trong FreeSql.Repository, tính năng lưu dữ liệu liên kết cho phép tự động lưu các đối tượng liên quan thông qua thuộc tính định hướng. Sau khi đã cấu hình các mối quan hệ giữa bảng, bài viết này sẽ hướng dẫn cách thực hiện lưu dữ liệu liên kết một cách hiệu quả.

Qua thực tế triển khai, quan hệ Nhiều-Đối-Một (Many-to-One) không phù hợp với cơ chế tự động lưu liên kết. Việc lưu chủ thể mà đồng thời tự động lưu cả thông tin thực thể cha phía trên là rất khó kiểm soát. FreeSql hiện không hỗ trợ lưu dữ liệu theo hướng từ dưới lên. Do đó, bài viết chỉ tập trung vào các quan hệ Một-Một, Một-Nhiều và Nhiều-Nhiều.

Lưu Thủ Công Bằng SaveMany

Phương thức này thực hiện đồng bộ toàn bộ dữ liệu, so sánh với dữ liệu hiện có trong cơ sở dữ liệu để xác định các thao tác thêm, sửa, xóa cần thực hiện.

var storage = dbContext.GetRepository<Category>();
var category = new Category
{
    Title = "Ngôn ngữ lập trình",
    Articles = new List<Article>
    {
        new Article { Title = "Bài viết 1", Content = "Nội dung mẫu" }
    }
};
storage.Insert(category);
storage.SaveMany(category, nameof(Category.Articles)); // Lưu thủ công danh sách Articles

Các điểm cần lưu ý:

  • Có thể xóa dữ liệu đã tồn tại trong bảng, bạn đã xác nhận?
  • Khi thuộc tính Articles rỗng, hệ thống sẽ xóa tất cả bài viết liên kết với category, bạn đã xác nhận?
  • Khi lưu Articles, hệ thống không tự động lưu các thuộc tính tập hợp cấp dưới của từng article, chỉ lưu ở cấp độ Articles hiện tại, bạn đã xác nhận?
  • Với quan hệ Nhiều-Nhiều, cơ chế sẽ so sánh và đồng bộ toàn bộ bảng trung gian, còn bảng ngoài chỉ được thêm mới không cập nhật.

Ví dụ về cấu trúc:

  • Bảng chính: Product
  • Bảng ngoài: Category
  • Bảng trung gian: ProductCategory

Lưu Tự Động Với EnableCascadeSave

Kích hoạt tùy chọn EnableCascadeSave trong DbContext hoặc Repository cho phép khi lưu đối tượng chính, hệ thống sẽ tự động đệ quy lưu các thuộc tính định hướng ở cấp Một-Một, Một-Nhiều và Nhiều-Nhiều.

Lưu ý: Chỉ nên sử dụng cho chức năng không quan trọng hoặc khi tạo dữ liệu thử nghiệm.

1. Lưu liên kết Một-Một

Từ phiên bản v3.2.606+, hỗ trợ lưu liên kết Một-Một và cả chức năng xóa liên kết.

2. Lưu liên kết Một-Nhiều (Chỉ thêm hoặc cập nhật, không xóa)

storage.DbContextOptions.EnableCascadeSave = true; // Cần kích hoạt thủ công
storage.Insert(category);
  • Không xóa dữ liệu đã tồn tại trong bảng con Articles, bạn đã xác nhận?
  • Khi thuộc tính Articles rỗng, không thực hiện thao tác nào, bạn đã xác nhận?
  • Khi lưu Articles, hệ thống sẽ tiếp tục lưu các thuộc tính tập hợp cấp dưới của từng article, đệ quy tối đa 18 cấp, bạn đã xác nhận?

Đệ quy 18 cấp có nghĩa là: Bảng Category có tập hợp Articles, Articles có tập hợp Comments. Khi lưu Category, hệ thống sẽ tự động lưu Articles, sau đó tiếp tục lưu Comments của từng article.

3. Lưu liên kết Nhiều-Nhiều

So sánh và đồng bộ toàn bộ bảng trung gian, còn bảng ngoài chỉ được thêm mới không cập nhật.

Cơ Chế Xóa Liên Kết

Cách 1: Xóa dựa trên đối tượng đã tải

Sử dụng với các đối tượng đã được tải qua Include/IncludeMany.

var storage = dbContext.GetRepository<UserRole>();
storage.DbContextOptions.EnableCascadeSave = true;
storage.Insert(new UserRole
{
    RoleName = "SuperAdmin",
    Accounts = new List<Account>
    {
        new Account { AccountName = "user1", Passcode = "hash1", Detail = new AccountDetail { Notes = "Thông tin bổ sung 1" } },
        new Account { AccountName = "user2", Passcode = "hash2", Detail = new AccountDetail { Notes = "Thông tin bổ sung 2" } }
    }
});

var roles = storage.Select
    .IncludeMany(r => r.Accounts, then => then.Include(a => a.Detail))
    .ToList();
storage.Delete(roles); // Xóa đệ quy tất cả thực thể liên kết

Cách 2: Xóa dựa trên điều kiện cơ sở dữ liệu

Xóa đệ quy theo điều kiện, không phụ thuộc vào khóa ngoại cơ sở dữ liệu.

var storage = dbContext.GetRepository<UserRole>();
var deletedData = storage.DeleteCascadeByDatabase(r => r.Id == 1);

Các lớp thực thể mẫu:

public class UserRole
{
    [Column(IsIdentity = true)]
    public int Id { get; set; }
    public string RoleName { get; set; }

    [Navigate(nameof(Account.RoleId))]
    public List<Account> Accounts { get; set; }
}

public class Account
{
    [Column(IsIdentity = true)]
    public int Id { get; set; }
    public string AccountName { get; set; }
    public string Passcode { get; set; }
    public int RoleId { get; set; }

    [Navigate(nameof(Id))]
    public AccountDetail Detail { get; set; }
}

public class AccountDetail
{
    [Column(IsPrimary = true)]
    public int AccountId { get; set; }
    public string Notes { get; set; }

    [Navigate(nameof(AccountId))]
    public Account Account { get; set; }
}

Thẻ: FreeSql FreeSql.Repository Cascade-Save csharp orm

Đăng vào ngày 24 tháng 9 lúc 15:47