EF Core - Quản lý mối quan hệ Một - Nhiều trong EF Core

Quản lý mối quan hệ Một - Nhiều trong Entity Framework Core

Entity Framework Core cung cấp một số cách tiếp cận để tạo, sửa đổi và xóa mối quan hệ một - nhiều.

Tạo mối quan hệ Một - Nhiều trong Entity Framework Core

Phần đầu tiên này chúng ta sẽ khám phá một số cách để tạo ra mối quan hệ một - nhiều giữa một thực thể chính hiện có và những thực thể phụ thuộc mới được tạo.

Thêm thực thể phụ thuộc vào thuộc tính điều hướng tập hợp của thực thể chính

Trong ví dụ này, một tác giả hiện có được lấy từ cơ sở dữ liệu bằng cách sử dụng phương thức DbSet.Find. Sau đó, một cuốn sách mới được tạo sẽ được thêm vào thuộc tính điều hướng tập hợp Books của tác giả.

using (var db = new TestContext())
{
    var book = new Book { Title = "King Lear" };
    var author = db.Authors.Find(1);
    author.Books.Add(book);
    db.SaveChanges();
}

Cách tiếp cận này có khả năng dẫn đến hai lệnh gọi đến cơ sở dữ liệu. Trước tiên là phương thức Find, nó sẽ kiểm tra bộ đệm để xem có tác giả nào có giá trị khóa chính là 1 đang được theo dõi bởi context hay không.

Nếu tác giả hiện không được theo dõi, một lệnh sẽ được đưa ra để lấy tác giả từ cơ sở dữ liệu. Sau đó, một lệnh khác sẽ chèn sách vào bảng Books:

exec sp_executesql N'SELECT TOP(1) [e].[AuthorId], [e].[FirstName], [e].[LastName]
FROM [Authors] AS [e]
WHERE [e].[AuthorId] = @__get_Item_0',N'@__get_Item_0 int',@__get_Item_0=1
exec sp_executesql N'SET NOCOUNT ON;
INSERT INTO [Books] ([AuthorId], [Title])
VALUES (@p0, @p1);
SELECT [BookId]
FROM [Books]
WHERE @@ROWCOUNT = 1 AND [BookId] = scope_identity();
',N'@p0 int,@p1 nvarchar(255)',@p0=1,@p1=N'King Lear'

Đính kèm thực thể giả mạo sau đó thêm thực thể phụ thuộc vào nó

"Thực thể giả mạo" hoặc "thực thể sơ khai" được sử dụng để đại diện cho tác giả trong ví dụ này, sau đó được gắn vào context.

Entity Framework Core bắt đầu theo dõi tác giả giả mạo với trạng thái là Unchanged. Khi sách được thêm vào thuộc tính tham chiếu tập hợp Books của tác giả được theo dõi, trạng thái của sách được thiết lập thành Added.

using (var db = new TestContext())
{
    var book = new Book { Title = "As You Like It" };
    var author = new Author { AuthorId = 1 };
    db.Attach(author);
    author.Books.Add(book);
    db.SaveChanges();
}

Cách tiếp cận này dẫn đến chỉ một lệnh gọi đến cơ sở dữ liệu - chèn sách mới vào cơ sở dữ liệu.

exec sp_executesql N'SET NOCOUNT ON;
INSERT INTO [Books] ([AuthorId], [Title])
VALUES (@p0, @p1);
SELECT [BookId]
FROM [Books]
WHERE @@ROWCOUNT = 1 AND [BookId] = scope_identity();
',N'@p0 int,@p1 nvarchar(255)',@p0=1,@p1=N'As You Like It'

Thiết lập giá trị khoá ngoại của sách mới một cách rõ ràng

Cả hai ví dụ trước đều đưa ra cách tiếp cận hướng đối tượng hơn để tạo mối quan hệ giữa các thực thể.

Trong ví dụ dưới đây, thực thể sách được tạo và có giá trị thuộc tính khóa ngoại hợp lệ. Không có tham chiếu đến một thực thể Author trong mã này:

using (var db = new TestContext())
{
    var book = new Book 
    { 
        Title = "The Winters Tale", 
        AuthorId = 1 
    };
    db.Add(book);
    db.SaveChanges();
}

Như với cách tiếp cận trước, điều này dẫn đến chỉ một lệnh gọi tới cơ sở dữ liệu:

exec sp_executesql N'SET NOCOUNT ON;
INSERT INTO [Books] ([AuthorId], [Title])
VALUES (@p0, @p1);
SELECT [BookId]
FROM [Books]
WHERE @@ROWCOUNT = 1 AND [BookId] = scope_identity();
',N'@p0 int,@p1 nvarchar(255)',@p0=1,@p1=N'The Winters Tale'

Sửa đổi mối quan hệ Một - Nhiều trong Entity Framework Core

Các ví dụ tiếp theo mô tả việc sửa đổi mối quan hệ một - nhiều giữa các thực thể.

Sử dụng thực thể giả mạo để chuyển thực thể phụ thuộc sang thực thể chính khác

Ví dụ này dẫn đến một cuốn sách hiện có với giá trị khóa chính là 4 được gán cho tác giả có giá trị khóa là 1.

Trong ví dụ này, thực thể sách giả mạo được gắn vào context, nó cho context biết rằng thực thể sách giả mạo có khóa được chỉ định đã tồn tại.

using(var db = new TestContext())
{
    var book = new Book { BookId = 4 };
    db.Attach(book);
    var author = new Author { AuthorId = 1 };
    db.Attach(author);
    author.Books.Add(book);
    db.SaveChanges();
}

Một lệnh cơ sở dữ liệu được tạo, cập nhật giá trị khóa ngoại của sách.

exec sp_executesql N'SET NOCOUNT ON;
UPDATE [Books] SET [AuthorId] = @p0
WHERE [BookId] = @p1;
SELECT @@ROWCOUNT;
',N'@p1 int,@p0 int',@p1=4,@p0=1

Thay đổi giá trị khóa ngoại của thực thể giả mạo

Trong ví dụ này, giá trị khóa ngoại của thực thể sách giả mạo được chỉ định rõ ràng.

using(var db = new TestContext())
{
    var book = new Book { BookId = 4 };
    db.Attach(book);
    book.AuthorId = 2;
    db.SaveChanges();
}

Một lần nữa, chỉ một câu lệnh cơ sở dữ liệu được tạo.

exec sp_executesql N'SET NOCOUNT ON;
UPDATE [Books] SET [AuthorId] = @p0
WHERE [BookId] = @p1;
SELECT @@ROWCOUNT;
',N'@p1 int,@p0 int',@p1=4,@p0=2

Thêm thực thể phụ thuộc vào thuộc tính tập hợp của thực thể chính mới

Phương thức Find được sử dụng để lấy thực thể sách và thực thể tác giả từ cơ sở dữ liệu.

using(var db = new TestContext())
{
    var book = db.Books.Find(4);
    var author = db.Authors.Find(2);
    author.Books.Add(book);
    db.SaveChanges();
}

Từ quan điểm hoạt động cơ sở dữ liệu, cách tiếp cận này có thể khá tốn kém, dẫn đến có thể có ba lệnh SQL được thực thi như sau:

exec sp_executesql N'SELECT TOP(1) [e].[BookId], [e].[AuthorId], [e].[Title]
FROM [Books] AS [e]
WHERE [e].[BookId] = @__get_Item_0',N'@__get_Item_0 int',@__get_Item_0=4
exec sp_executesql N'SELECT TOP(1) [e].[AuthorId], [e].[FirstName], [e].[LastName]
FROM [Authors] AS [e]
WHERE [e].[AuthorId] = @__get_Item_0',N'@__get_Item_0 int',@__get_Item_0=2
exec sp_executesql N'SET NOCOUNT ON;
UPDATE [Books] SET [AuthorId] = @p0
WHERE [BookId] = @p1;
SELECT @@ROWCOUNT;
',N'@p1 int,@p0 int',@p1=4,@p0=2

Xóa bỏ mối quan hệ Một - Nhiều trong Entity Framework Core

Xóa thực thể chính

Xóa thực thể chính sẽ đảm bảo rằng hành động được chỉ định bởi Hành động ràng buộc tham chiếu sẽ được thực thi.

Đối với các mối quan hệ bắt buộc, tất cả những phần tử phụ thuộc sẽ bị xóa. Nếu mối quan hệ là tùy chọn, các giá trị khóa ngoại của các phần tử phụ thuộc sẽ được thiết lập thành null.

using(var db = new TestContext())
{
    var authorToDelete = new Author { AuthorId = 1 };
    db.Authors.Remove(authorToDelete);
    db.SaveChanges();
}
exec sp_executesql N'SET NOCOUNT ON;
DELETE FROM [Authors]
WHERE [AuthorId] = @p0;
SELECT @@ROWCOUNT;
',N'@p0 int',@p0=2

Thiết lập giá trị khóa ngoại thành null (chỉ các mối quan hệ tùy chọn)

Nếu mối quan hệ là tùy chọn, bạn có thể đặt giá trị khóa ngoại thành null để xóa mối quan hệ.

using (var db = new TestContext())
{
    var book = context.Books.Find(1);
    book.AuthorId = null;
    db.SaveChanges();
}

Một lần nữa, việc sử dụng phương thức Find này có thể dẫn đến hai lệnh gọi đến cơ sở dữ liệu:

exec sp_executesql N'SELECT TOP(1) [e].[BookId], [e].[AuthorId], [e].[Title]
FROM [Books] AS [e]
WHERE [e].[BookId] = @__get_Item_0',N'@__get_Item_0 int',@__get_Item_0=1
exec sp_executesql N'SET NOCOUNT ON;
UPDATE [Books] SET [AuthorId] = @p0
WHERE [BookId] = @p1;
SELECT @@ROWCOUNT;
',N'@p1 int,@p0 int',@p1=1,@p0=NULL

Bạn cũng có thể thực hiện thao tác này bằng cách sử dụng thực thể giả mạo như sau:

var book = new Book { BookId = 2 } ;
db.Attach(book);
book.AuthorId = null;
db.Entry(book).Property(p => p.AuthorId).IsModified = true;
db.SaveChanges();
exec sp_executesql N'SET NOCOUNT ON;
UPDATE [Books] SET [AuthorId] = @p0
WHERE [BookId] = @p1;
SELECT @@ROWCOUNT;
',N'@p1 int,@p0 int',@p1=2,@p0=NULL

Xóa thực thể phụ thuộc khỏi tập hợp của thực thể chính

Bạn có thể xóa thực thể phụ thuộc khỏi thuộc tính tập hợp của thực thể chính:

using(var db = new TestContext())
{
    var book = db.Books.Find(1);
    var author = db.Authors.Find(1);
    author.Books.Remove(book);
    db.SaveChanges();
}

 

Lưu ý rằng thao tác này sẽ xóa sách trong một mối quan hệ bắt buộc và thiết lập giá trị khóa ngoại của phần tử phụ thuộc thành null trong một mối quan hệ tùy chọn