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.
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.
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'
"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'
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'
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ể.
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
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
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 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
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
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.
Bạn có thể vui lòng tắt trình chặn quảng cáo ❤️ để hỗ trợ chúng tôi duy trì hoạt động của trang web.
Bài viết này sẽ giúp bạn tìm hiểu về bộ chuyển đổi giá trị - một trong những cải tiến mạnh mẽ của Entity Framework Core 5.
Trong bài viết này, chúng ta sẽ khám phá cách làm việc với các tính năng của Entity Framework Core 5 (EF Core) để thực thi truy vấn SQL thô.
Với EF Core 5, chúng ta có thể thêm view vào trong DbContext và tạo view trong database bằng cách sử dụng cơ chế chuyển đổi cơ sở dữ liệu tích hợp sẵn.
Bài viết này sẽ khám phá các mối quan hệ trong cơ sở dữ liệu quan hệ và cách mô hình hóa các mối quan hệ đó bằng cách tiếp cận Code First trong EF Core.