Câu hỏi DbSet.Attach (thực thể) vs DbContext.Entry (thực thể) .State = EntityState.Modified


Khi tôi đang ở trong một kịch bản tách rời và nhận được một dto từ khách hàng mà tôi ánh xạ vào một thực thể để lưu nó, tôi làm điều này:

context.Entry(entity).State = EntityState.Modified;
context.SaveChanges();

Đối với những gì sau đó là DbSet.Attach(entity)

hoặc tại sao tôi nên sử dụng phương thức .Attach khi EntityState.Modified đã gắn thực thể?


76
2018-06-22 19:03


gốc


Tốt hơn nên thêm một số thông tin phiên bản, điều này đã được yêu cầu trước đó. Tôi không rõ nếu điều này xứng đáng là một câu hỏi mới. - Henk Holterman


Các câu trả lời:


Khi bạn làm context.Entry(entity).State = EntityState.Modified;, bạn không chỉ gắn thực thể vào DbContext, bạn cũng đang đánh dấu toàn bộ thực thể là bẩn. Điều này có nghĩa là khi bạn làm context.SaveChanges(), EF sẽ tạo một câu lệnh cập nhật sẽ cập nhật tất cả các các trường của thực thể.

Điều này không phải lúc nào cũng mong muốn.

Mặt khác, DbSet.Attach(entity) gắn thực thể vào ngữ cảnh không có đánh dấu nó bẩn. Nó tương đương với việc làm context.Entry(entity).State = EntityState.Unchanged;

Khi đính kèm theo cách này, trừ khi bạn tiến hành cập nhật thuộc tính trên thực thể, lần sau bạn gọi context.SaveChanges(), EF sẽ không tạo bản cập nhật cơ sở dữ liệu cho thực thể này.

Ngay cả khi bạn đang lập kế hoạch thực hiện cập nhật cho một thực thể, nếu thực thể có nhiều thuộc tính (cột db) nhưng bạn chỉ muốn cập nhật một số, bạn có thể thấy thuận lợi để thực hiện DbSet.Attach(entity)và sau đó chỉ cập nhật một số thuộc tính cần cập nhật. Làm theo cách này sẽ tạo ra một tuyên bố cập nhật hiệu quả hơn từ EF. EF sẽ chỉ cập nhật các thuộc tính bạn đã sửa đổi (trái ngược với context.Entry(entity).State = EntityState.Modified; điều này sẽ làm cho tất cả các thuộc tính / cột được cập nhật)

Tài liệu liên quan: Thêm / Đính kèm và Thực thể Hoa.

Ví dụ về mã

Giả sử bạn có thực thể sau:

public class Person
{
    public int Id { get; set; } // primary key
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

Nếu mã của bạn trông như thế này:

context.Entry(personEntity).State = EntityState.Modified;
context.SaveChanges();

SQL được tạo ra sẽ trông giống như sau:

UPDATE person
SET FirstName = 'whatever first name is',
    LastName = 'whatever last name is'
WHERE Id = 123; -- whatever Id is.

Lưu ý cách câu lệnh cập nhật ở trên sẽ cập nhật tất cả các cột, bất kể hoặc bạn có thực sự thay đổi các giá trị hay không.

Ngược lại, nếu mã của bạn sử dụng tệp đính kèm "bình thường" như sau:

context.People.Attach(personEntity); // State = Unchanged
personEntity.FirstName = "John"; // State = Modified, and only the FirstName property is dirty.
context.SaveChanges();

Sau đó, câu lệnh cập nhật được tạo khác nhau:

UPDATE person
SET FirstName = 'John'
WHERE Id = 123; -- whatever Id is.

Như bạn có thể thấy, câu lệnh cập nhật chỉ có cập nhật các giá trị đã thực sự thay đổi sau khi bạn đính kèm thực thể vào ngữ cảnh. Tùy thuộc vào cấu trúc bảng của bạn, điều này có thể có tác động hiệu suất tích cực.

Bây giờ, tùy chọn nào tốt hơn cho bạn phụ thuộc hoàn toàn vào những gì bạn đang cố gắng làm.


184
2018-06-22 19:24



Câu trả lời hay với chi tiết! - Elisabeth
EF không tạo ra mệnh đề WHERE theo cách này. Nếu bạn đính kèm một thực thể được tạo mới (tức là thực thể mới ()) và đặt nó thành sửa đổi, bạn phải đặt tất cả các trường ban đầu vì khóa lạc quan. Mệnh đề WHERE được tạo ra trong truy vấn UPDATE thường chứa tất cả các trường gốc (không chỉ là Id) vì vậy nếu bạn không làm như vậy EF sẽ ném một ngoại lệ đồng thời. - bubi
@ budi: Cảm ơn bạn đã phản hồi. Tôi đã kiểm tra lại để chắc chắn và đối với một thực thể cơ bản, nó hoạt động như tôi đã mô tả, với WHERE mệnh đề chỉ chứa khóa chính và không có bất kỳ kiểm tra đồng thời nào. Để kiểm tra đồng thời, tôi cần định cấu hình một cột rõ ràng dưới dạng mã thông báo đồng thời hoặc rowVersion. Trong trường hợp đó, WHERE mệnh đề sẽ chỉ có khóa chính và cột mã thông báo đồng thời, không phải tất cả các trường. Nếu các bài kiểm tra của bạn cho thấy nếu không, tôi rất thích nghe về nó. - sstan
làm thế nào tôi có thể tìm thấy tài sản phù thủy được sửa đổi? - Navid_pdp11
@ Navid_pdp11 DbContext.Entry(person).CurrentValues và DbContext.Entry(person).OriginalValues. - Shimmy


Khi bạn sử dụng DbSet.Update , Entity Framework đánh dấu tất cả các thuộc tính của thực thể của bạn EntityState.Modified, để theo dõi chúng. Nếu bạn muốn thay đổi chỉ một số thuộc tính của bạn, không phải tất cả chúng, hãy sử dụng DbSet.Attach. Phương pháp này làm cho tất cả các thuộc tính của bạn EntityState.Unchanged, vì vậy bạn phải tạo các thuộc tính mà bạn muốn cập nhật EntityState.Modified. Do đó, khi ứng dụng truy cập vào DbContext.SaveChanges, nó sẽ chỉ hoạt động các thuộc tính đã sửa đổi.


0
2017-09-15 07:27