2015-06-22 10 views
66

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:DbSet.Attach (thực thể) vs DbContext.Entry (thực thể) .State = EntityState.Modified

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

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

hoặc tại sao tôi nên sử dụng phương pháp .Attach khi EntityState.Modified đã gắn đơn vị?

+0

Tốt hơn hãy 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. –

Trả lời

158

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 bản cập nhật sẽ cập nhật tất 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 đơn vị với bối cảnh mà không đánh dấu nó bẩn. Nó tương đương với việc thực hiện 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 có ý định cập nhậ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 vài, bạn có thể thấy thuận lợi khi thực hiện DbSet.Attach(entity) và sau đó chỉ cập nhật vài 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; 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: Add/Attach and Entity States.

Mã dụ

Hãy nói rằng 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ẽ giống như thế này:

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ể bạn có thực sự thay đổi giá trị hay không.

Ngược lại, nếu mã của bạn sử dụng "bình thường" Đính kèm như thế này:

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

Sau đó, báo cáo cập nhật được tạo ra là khác nhau:

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

Như bạn có thể thấy, các báo cáo cập nhật chỉ 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.

+9

Câu trả lời hay với chi tiết! – Elisabeth

+0

EF không tạo 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 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

+1

@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 mệnh đề 'WHERE' 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 đó, mệnh đề 'WHERE' 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

0

Khi bạn sử dụng phương pháp DbSet.Update, Khung thực thể đánh dấu tất cả các thuộc tính của thực thể của bạn là EntityState.Modified, do đó theo dõi chúng. Nếu bạn chỉ muốn thay đổi một số thuộc tính của mình, không phải tất cả chúng, hãy sử dụng DbSet.Attach. Phương thức 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, ứng dụng sẽ chỉ hoạt động các thuộc tính đã sửa đổi.

Các vấn đề liên quan