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.
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