19

Tôi tìm thấy tôi đang bối rối về tải lười biếng vvEF: tải Lazy, bốc háo hức, và "liệt kê các đếm được"

Thứ nhất, là hai báo cáo tương đương:

(1) Lazy loading: 
_flaggedDates = context.FlaggedDates.Include("scheduledSchools") 
.Include ("interviews").Include("partialDayAvailableBlocks") 
.Include("visit").Include("events"); 

(2) Eager loading: 
_flaggedDates = context.FlaggedDates; 

Trong khác từ, trong (1) các "Bao gồm" gây ra các bộ sưu tập chuyển hướng/tài sản được nạp cùng với các bộ sưu tập cụ thể yêu cầu, bất kể thực tế là bạn đang sử dụng tải chậm ... phải không?

Và trong (2), câu lệnh sẽ tải tất cả các thực thể điều hướng ngay cả khi bạn không yêu cầu chúng cụ thể, vì bạn đang sử dụng tải mong muốn ... phải không?

Thứ hai: ngay cả khi bạn đang sử dụng tải háo hức, dữ liệu sẽ không thực sự được tải về từ cơ sở dữ liệu cho đến khi bạn "liệt kê các đếm được", như trong đoạn mã sau:

var dates = from d in _flaggedDates 
      where d.dateID = 2 
      select d; 
foreach (FlaggedDate date in dates) 
{ 
... etc. 
} 

Các dữ liệu sẽ không thực sự được tải xuống ("liệt kê") cho đến khi vòng lặp foreach ... phải không? Nói cách khác, dòng "var dates" định nghĩa truy vấn, nhưng truy vấn không được thực hiện cho đến vòng lặp foreach.

Cho rằng (nếu giả định của tôi là chính xác), sự khác biệt thực sự giữa tải mong muốn và tải chậm là gì ?? Dường như trong cả hai trường hợp, dữ liệu không xuất hiện cho đến khi đếm. Tui bỏ lỡ điều gì vậy?

(kinh nghiệm cụ thể của tôi là với mã đầu tiên, phát triển POCO, bằng cách này ... mặc dù những câu hỏi có thể áp dụng tổng quát hơn.)

+0

EntityFramework sử dụng tải mong muốn/lười biếng (thuật ngữ phần mềm chung cho cách dữ liệu được tải) để tìm nạp các đối tượng và bộ sưu tập liên quan. Deffered Query Execution là một tạo phẩm của LINQ cho phép các truy vấn linh hoạt hơn (chúng có thể không được thực hiện ở tất cả trong một số trường hợp). – jwize

Trả lời

17

Mô tả của bạn (1) là đúng, nhưng nó là một ví dụ của Eager Đang tải hơn là Tải xuống Lười.

Mô tả của bạn về (2) không chính xác. (2) về mặt kỹ thuật là không sử dụng tải nào cả, nhưng sẽ sử dụng Tải Lười Biếng nếu bạn cố gắng truy cập vào bất kỳ giá trị không vô hướng nào trên FlaggedDates của bạn.

Trong cả hai trường hợp, bạn chính xác không có dữ liệu nào được tải từ kho dữ liệu của bạn cho đến khi bạn cố gắng "làm điều gì đó" với _flaggedDates. Tuy nhiên, những gì xảy ra là khác nhau trong mỗi trường hợp.

(1): Đang tải: ngay khi bạn bắt đầu vòng for, mọi đối tượng bạn đã chỉ định sẽ được lấy từ cơ sở dữ liệu và được tích hợp vào cấu trúc dữ liệu khổng lồ trong bộ nhớ. Đây sẽ là một hoạt động rất tốn kém, kéo một lượng lớn dữ liệu từ cơ sở dữ liệu của bạn. Tuy nhiên, tất cả sẽ xảy ra trong một chuyến đi vòng cơ sở dữ liệu, với một truy vấn SQL đơn được thực thi.

(2): Tải trọng lười: Khi bắt đầu vòng lặp for của bạn, nó sẽ chỉ tải các đối tượng được gắn cờ. Tuy nhiên, nếu bạn truy cập các đối tượng liên quan bên trong vòng lặp for của bạn, nó sẽ không có các đối tượng đó được nạp vào bộ nhớ. Nỗ lực đầu tiên để truy xuất các scheduledSchools cho một FlaggedDate đã cho sẽ dẫn đến một vòng tròn cơ sở dữ liệu mới để truy xuất các trường, hoặc một ngoại lệ được ném ra vì ngữ cảnh của bạn đã được xử lý. Vì bạn muốn truy cập bộ sưu tập theo lịch biểu trong một vòng lặp for, bạn sẽ có một chuyến đi vòng cơ sở dữ liệu mới cho mọi FlaggedDate mà ban đầu bạn đã nạp vào đầu vòng lặp for.

Phản hồi nhận xét

Tắt tính năng Tải xuống không giống như Kích hoạt tính năng Tải công việc.Trong ví dụ này:

context.ContextOptions.LazyLoadingEnabled = false; 
var schools = context.FlaggedDates.First().scheduledSchools; 

Biến schools sẽ chứa một EntityCollection rỗng, bởi vì tôi đã không Include chúng trong truy vấn ban đầu (FlaggedDates.First()), và tôi vô hiệu hóa tải lười biếng để họ không thể được tải sau khi truy vấn ban đầu đã được thực hiện.

Bạn đúng là where d.dateID == 2 có nghĩa là chỉ các đối tượng liên quan đến đối tượng FlaggedDate cụ thể đó sẽ được kéo vào. Tuy nhiên, tùy thuộc vào số lượng đối tượng có liên quan đến FlaggedDate đó, bạn vẫn có thể kết thúc với nhiều dữ liệu đi qua dây đó. Điều này là do cách EntityFramework xây dựng ra truy vấn SQL của nó. Kết quả truy vấn SQL luôn ở định dạng bảng, nghĩa là bạn phải có cùng số cột cho mỗi hàng. Đối với mỗi đối tượng được lập lịch, cần phải có ít nhất một hàng trong tập kết quả và vì mỗi hàng phải chứa ít nhất một số giá trị cho mỗi cột, bạn kết thúc với mọi giá trị vô hướng trên đối tượng FlaggedDate của bạn được lặp lại. Vì vậy, nếu bạn có 10 trường được lên lịch và 10 cuộc phỏng vấn được liên kết với FlaggedDate của mình, bạn sẽ kết thúc với 20 hàng mà mỗi hàng chứa mọi giá trị vô hướng trên FlaggedDate. Một nửa số hàng sẽ có giá trị null cho tất cả các cột ScheduledSchool và nửa còn lại sẽ có giá trị null cho tất cả các cột Phỏng vấn.

Trường hợp điều này thực sự tồi tệ, là nếu bạn đi "sâu" trong dữ liệu bạn đang đưa vào. Ví dụ: nếu mỗi ScheduledSchool có thuộc tính students, bạn cũng bao gồm, thì đột nhiên bạn sẽ có một hàng cho mỗi Sinh viên trong mỗi ScheduledSchool và trên mỗi hàng đó, mọi giá trị vô hướng cho ScheduledSchool của Sinh viên sẽ được bao gồm (thậm chí mặc dù chỉ các giá trị của hàng đầu tiên cuối cùng được sử dụng), cùng với mọi giá trị vô hướng trên đối tượng FlaggedDate ban đầu. Nó có thể tăng lên nhanh chóng.

Rất khó để giải thích bằng văn bản, nhưng nếu bạn nhìn vào dữ liệu thực tế quay lại từ truy vấn có nhiều số Include, bạn sẽ thấy rằng có rất nhiều dữ liệu trùng lặp. Bạn có thể sử dụng LinqPad để xem các truy vấn SQL được tạo bởi mã EF của bạn.

+0

Đối với (1) (MY (1), tôi có nghĩa là Lazy Loading đã được kích hoạt.Các tuyên bố là một ví dụ về tải mong muốn vì Bao gồm .. phải không? – Cynthia

+0

Cho (2) (MY (2)) ... Nếu Lazy Loading được DISABLED (nói cách khác háo hức tải là có hiệu lực), bạn đang nói rằng các thuộc tính chuyển hướng sẽ không được nạp cùng với FlaggedDates? Sau đó, những gì hiện mong muốn tải có nghĩa là? – Cynthia

+0

Đáp ứng chỉnh sửa của bạn: OK, tôi thấy những gì bạn đang nói Nhưng đối với điểm số 1 của bạn: tất cả các đối tượng sẽ được kéo vào, nhưng chỉ những đối tượng được chỉ định trong truy vấn của bạn, đúng không? Ví dụ, trong ví dụ của tôi tôi đã nói d.dateID == 2, vì vậy chỉ các đối tượng cho đối tượng FlaggedDate với dateID = 2 sẽ có dữ liệu được kéo vào. Phải không? Vì vậy, nó sẽ không quá tốn kém miễn là bạn đã giới hạn phạm vi trong truy vấn của bạn – Cynthia

0

Không có sự khác biệt. Điều này không đúng trong EF 1.0, không hỗ trợ tải háo hức (ít nhất là không tự động). Trong 1.0, bạn phải sửa đổi thuộc tính để tải tự động hoặc gọi phương thức Load() trên tham chiếu thuộc tính.

Một điều cần lưu ý là những người Bao gồm thể đi tan thành mây khói nếu bạn truy vấn trên nhiều đối tượng như vậy:

from d in ctx.ObjectDates.Include("MyObjectProperty") 
from da in d.Days 

ObjectDate.MyObjectProperty sẽ không tự động nạp.