2014-12-16 14 views
8

Tôi đang viết một số mã để truy cập cơ sở dữ liệu bằng EntityFrameWork. Mã này là:Tại sao tôi cần một ToList() để tránh các lỗi ngữ cảnh được xử lý?

public IEnumerable<Rows> GetRows(int id) 
{ 
    using (var context = new ApplicationDbContext()) 
    { 
     var repository = new EntityFrameWorkRepository<int, RowEntity>(context); 
     //need a ToList() here to prevent disposed dbcontext errors 
     return repository.GetRowsFromDb(id).ToList(); 
    } 
} 

GetRowsFromDb() sử dụng LINQ để truy vấn cơ sở dữ liệu và lọc kết quả bằng id. Tôi đã viết phương thức trên mà không có cuộc gọi ToList(), nhưng khi tôi cố truy cập các đối tượng trong IEnumerable đã được trả lại, tôi sẽ nhận được một ngoại lệ về dbcontext đã được xử lý. Tôi không hiểu làm thế nào mã trên sửa chữa mọi thứ, mặc dù nó sau đó làm việc. Tôi giả sử ToList() là sâu sao chép các đối tượng và rằng điều này có lẽ cung cấp sự tách biệt cần thiết từ bối cảnh/cơ sở dữ liệu, nhưng chắc chắn các đối tượng ban đầu nên có thể sử dụng?

+4

'IEnumerables' rất lười, vì vậy ngữ cảnh sẽ được xử lý trước khi bất kỳ kết quả nào được tìm nạp trong phương thức gọi. 'ToList' khiến mọi thứ trở nên háo hức. – Lee

+0

Tìm kiếm 'LINQ deffered execution' – MarcinJuraszek

+0

Liên quan ngẫu nhiên: http://stackoverflow.com/questions/27491762/creating-a-plan-repository-but-using-keyword-in-constructor-body/27491794#27491794 – BradleyDotNET

Trả lời

8

Lý do bạn cần phải gọi ToList, ToArray, hoặc một số phương pháp khác mà liệt kê các dữ liệu trả về bởi EF là thực hiện truy vấn trong LINQ được hoãn: dữ liệu không được xử lý cho đến khi bạn mang nó một cách rõ ràng. Vào thời điểm phương thức của bạn trả về ngữ cảnh mà dữ liệu truy vấn đã thu được được đóng lại (khối using của bạn sẽ xử lý điều đó xảy ra nhanh chóng), gây ra ngoại lệ mà bạn thấy.

Việc này được thực hiện để mã không dành thời gian xử lý dữ liệu mà bạn không cần. Ví dụ: bạn có thể viết mã bắt đầu đọc qua dữ liệu ở phía máy khách và dừng ở giữa. Nếu việc thực thi truy vấn không bị trì hoãn, bạn sẽ dành thời gian và bộ nhớ để lấy "đuôi" của truy vấn chỉ để vứt nó đi. Thực thi hoãn lại cho phép bạn kiểm soát: bạn quyết định dữ liệu nào bạn muốn giữ lại khi bạn đi hoặc mang toàn bộ bộ sưu tập vào bộ nhớ dựa trên những gì bạn định làm với dữ liệu.

7

Nếu bạn không gọi .ToList() sự đếm được sẽ được đánh giá sau khoản using của bạn kết thúc, và do đó bối cảnh dữ liệu sẽ được xử lý trước khi đánh giá truy vấn.

IMO, bạn nên xem xét việc làm cho kho lưu trữ của bạn xử lý việc này (bằng cách gọi .ToList()) nếu không thì vấn đề này đại diện cho chi tiết triển khai bị rò rỉ.

1

Nếu không có ToList() bạn chỉ trả về điều tra viên không thu thập thực tế đối tượng. Các đối tượng thực tế được tìm nạp khi bạn cố truy cập bộ sưu tập. Nhưng trong trường hợp này những gì bạn cần là một bối cảnh và kho lưu trữ, bởi vì bạn truy cập chúng từ cơ sở dữ liệu. Nhưng vì nó đã nằm ngoài phạm vi của điều khoản using cả hai đều được xử lý do đó ngoại lệ.

1

tôi giả ToList() là sao chép các đối tượng sâu

Không chính xác - trước khi bạn gọi ToList tất cả các bạn có là một truy vấn . bạn không nhận được kết quả cho đến khi bạn liệt kê hoặc biến nó thành bộ sưu tập cụ thể qua ToList, ToArray, etc.

chắc chắn đối tượng ban đầu có thể sử dụng được?

Không - nó đã được xử lý, đó là cách bạn nói với hệ thống rằng đối tượng đã thực hiện công việc của mình và không còn cần thiết nữa.Thực tế là bạn vẫn có một truy vấn chưa được thực hiện không giữ ngữ cảnh ở trạng thái có thể sử dụng được.

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