I. Eager Loading

Eager loading là quá trình nhờ đó một truy vấn cho một kiểu của thực thể cũng tải những thực thể liên quan như một phần của truy vấn. Eager loading được thực hiện bằng cách sử dụng phương thức Include().

Trong ví dụ sau nó lấy tất cả những sinh viên từ CSDL cùng với trình độ của nó sử dụng phương thức Include()

LINQ Query Syntax:

  
        using (var context = new SchoolDBEntities())
        {
            var res = (from s in context.Students.Include("Standard")
                        where s.StudentName == "Student1"
                        select s).FirstOrDefault<Student>();
        }

LINQ Method Syntax:

    
    using (var ctx = new SchoolDBEntities())
        {
            stud = ctx.Students.Include("Standard")
                               .Where(s => s.StudentName == "Student1").FirstOrDefault<Student>();
           
        }

Đoạn mã trên sẽ có kết quả như truy vấn SQL sau:

SELECT TOP (1) 
[Extent1].[StudentID] AS [StudentID], 
[Extent1].[StudentName] AS [StudentName], 
[Extent2].[StandardId] AS [StandardId], 
[Extent2].[StandardName] AS [StandardName], 
[Extent2].[Description] AS [Description]
FROM  [dbo].[Student] AS [Extent1]
LEFT OUTER JOIN [dbo].[Standard] AS [Extent2] ON [Extent1].[StandardId] = [Extent2].[StandardId]
WHERE 'Student1' = [Extent1].[StudentName]

Use Lambda Expression:

Bạn cũng có thể sử dụng LINQ lambda expression trong phương thức Include. Để làm điều này lấy một tham chiếu của System.Data.Entity namespace và sử dụng lambda expression như dưới đây:

using System;
using System.Data.Entity; 
   
class Program
{
    static void Main(string[] args)
    {
    
        using (var ctx = new SchoolDBEntities())
        {
            stud = ctx.Students.Include(s => s.Standard)
                                .Where(s => s.StudentName == "Student1")
                                .FirstOrDefault<Student>();
           
        }
    }
}

Đoạn mã trên sẽ có kết quả như truy vấn SQL sau:

SELECT TOP (1) 
[Extent1].[StudentID] AS [StudentID], 
[Extent1].[StudentName] AS [StudentName], 
[Extent2].[StandardId] AS [StandardId], 
[Extent2].[StandardName] AS [StandardName], 
[Extent2].[Description] AS [Description]
FROM  [dbo].[Student] AS [Extent1]
LEFT OUTER JOIN [dbo].[Standard] AS [Extent2] ON [Extent1].[StandardId] = [Extent2].[StandardId]
WHERE 'Student1' = [Extent1].[StudentName]

Tải nhiều cấp của những thực thể liên quan:

Bạn cũng có thể eagerly load nhiều cấp của những thực thể liên quan. Đoạn mã sau tải Student, Standard và Teachers liên quan:

using (var ctx = new SchoolDBEntities())
    {
        stud = ctx.Students.Include("Standard.Teachers")
                            .Where(s => s.StudentName == "Student1")
                            .FirstOrDefault<Student>();
    }

Hoặc sử dụng lambda expression như bên dưới:

using (var ctx = new SchoolDBEntities())
    {
        stud = ctx.Students.Include(s => s.Standard.Teachers)
                            .Where(s => s.StudentName == "Student1")
                            .FirstOrDefault<Student>();
    }

Đoạn mã trên có kết quả như truy vấn SQL sau:

SELECT [Project2].[StudentID] AS [StudentID], 
[Project2].[StudentName] AS [StudentName], 
[Project2].[StandardId] AS [StandardId], 
[Project2].[StandardName] AS [StandardName], 
[Project2].[Description] AS [Description], 
[Project2].[C1] AS [C1], 
[Project2].[TeacherId] AS [TeacherId], 
[Project2].[TeacherName] AS [TeacherName], 
[Project2].[StandardId1] AS [StandardId1]
FROM ( SELECT 
    [Limit1].[StudentID] AS [StudentID], 
    [Limit1].[StudentName] AS [StudentName], 
    [Limit1].[StandardId1] AS [StandardId], 
    [Limit1].[StandardName] AS [StandardName], 
    [Limit1].[Description] AS [Description], 
    [Project1].[TeacherId] AS [TeacherId], 
    [Project1].[TeacherName] AS [TeacherName], 
    [Project1].[StandardId] AS [StandardId1], 
    CASE WHEN ([Project1].[TeacherId] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C1]
    FROM   (SELECT TOP (1) [Extent1].[StudentID] AS [StudentID], [Extent1].[StudentName] AS [StudentName], [Extent1].[StandardId] AS [StandardId2], [Extent2].[StandardId] AS [StandardId1], [Extent2].[StandardName] AS [StandardName], [Extent2].[Description] AS [Description]
        FROM  [dbo].[Student] AS [Extent1]
        LEFT OUTER JOIN [dbo].[Standard] AS [Extent2] ON [Extent1].[StandardId] = [Extent2].[StandardId]
        WHERE 'updated student' = [Extent1].[StudentName] ) AS [Limit1]
    LEFT OUTER JOIN  (SELECT 
        [Extent3].[TeacherId] AS [TeacherId], 
        [Extent3].[TeacherName] AS [TeacherName], 
        [Extent3].[StandardId] AS [StandardId]
        FROM [dbo].[Teacher] AS [Extent3]
        WHERE [Extent3].[StandardId] IS NOT NULL ) AS [Project1] ON [Limit1].[StandardId2] = [Project1].[StandardId]
)  AS [Project2]
ORDER BY [Project2].[StudentID] ASC, [Project2].[StandardId] ASC, [Project2].[C1] ASC

II. Lazy Loading

Một trong những chức năng quan trọng của Entity Framework là lazy loading. Lazy loading có nghĩa là trì hoãn việc tải những dữ liệu liên quan cho tới khi bạn đưa ra yêu cụ thể cho nó. VD: Lớp Student chứa StudentAddress như một thuộc tính complex. Vì vậy đầu tiên context tải tất cả những sinh viên từ CSDL rồi sau đó nó sẽ tải địa chỉ của một sinh viên riêng biệt khi chúng ta truy cập thuộc tính StudentAddress như bên dưới:

using (var ctx = new SchoolDBEntities())
    {
        //Loading students only
        IList<Student> studList = ctx.Students.ToList<Student>();

        Student std = studList[0];

        //Loads Student address for particular Student only (seperate SQL query)
        StudentAddress add = std.StudentAddress;
    }

Đoạn mã trên sẽ có kết quả trong hai truy vấn SQL. Đầu tiên nó sẽ tìm nạp tất cả sinh viên:

SELECT 
[Extent1].[StudentID] AS [StudentID], 
[Extent1].[StudentName] AS [StudentName], 
[Extent1].[StandardId] AS [StandardId]
FROM [dbo].[Student] AS [Extent1]

Rồi sau đó nó sẽ gửi truy vấn sau khi chúng ta nhận tham chiếu của StudentAddress:

exec sp_executesql N'SELECT 
[Extent1].[StudentID] AS [StudentID], 
[Extent1].[Address1] AS [Address1], 
[Extent1].[Address2] AS [Address2], 
[Extent1].[City] AS [City], 
[Extent1].[State] AS [State]
FROM [dbo].[StudentAddress] AS [Extent1]
WHERE [Extent1].[StudentID] = @EntityKeyValue1',N'@EntityKeyValue1 int',@EntityKeyValue1=1

Tuy nhiên bạn cũng có thể tắt lazy loading cho một thuộc tính riêng biệt hoặc toàn bộ context. Để tắt lazy loading cho một thuộc tính riêng biệt đừng cài nó là virtual. Để tắt lazy loading cho tất cả những thực thể trong context, cài thuộc tính configuration của nó thành false:

using System;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Data.Entity.Core.Objects;
using System.Linq;
    
public partial class SchoolDBEntities : DbContext
{
    public SchoolDBEntities(): base("name=SchoolDBEntities")
    {
        this.Configuration.LazyLoadingEnabled = false;
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        throw new UnintentionalCodeFirstException();
    }
}

Những quy tắc cho lazy loading:

  1. context.Configuration.ProxyCreationEnabled nên là true.
  2. context.Configuration.LazyLoadingEnabled nên là true.
  3. Thuộc tính điều hướng nên được định nghĩa là public, virtual. Context sẽ không thực hiện lazy loading nếu thuộc tính không được định nghĩa là virtual.

III. Explicit Loading với DBContext

Thậm chí với lazy loading bị tắt, nó vẫn có thể lazy load những thực thể liên quan nhưng nó phải được thực hiện với một explicit call. Sử dụng phương thức Load của đối tượng DBEntityEntry để thực hiện việc này.

Đoạn mã sau explicitly loads Standard của Student riêng biệt sử dụng phương thức Reference() của DbEntityEntry:

using (var context = new SchoolDBEntities())
{
    //Disable Lazy loading
    context.Configuration.LazyLoadingEnabled = false;
                
    var student = (from s in context.Students
                        where s.StudentName == "Bill"
                        select s).FirstOrDefault<Student>();

    context.Entry(student).Reference(s => s.Standard).Load();
}     

Nếu bạn chạy đoạn mã trên bạn có thể nhìn thấy đầu tiên nó tải sinh viên mà không phải standard như bên dưới:

Entity Framework tutorial 4.3 dbcontext

Phương thức load để nhận thực thể Standard là như bên dưới:

Entity Framework tutorial 4.3 dbcontext

Đoạn mã trên sẽ thực thi hai truy vấn CSDL khác nhau. Truy vấn đầu tiên nhận Student và truy vấn thứ hai nhận Standard.

Load collection:

Sử dụng phương thức Collection() thay vì phương thức Reference() để tải tập hợp thuộc tính điều hướng. Ví dụ sau tải những khóa học của sinh viên.

using (var context = new SchoolDBEntities())
{
    context.Configuration.LazyLoadingEnabled = false;
                
    var student = (from s in context.Students
                        where s.StudentName == "Bill"
                        select s).FirstOrDefault<Student>();

    context.Entry(student).Collection(s => s.Courses).Load();
}

Note: Phương thức Load mở rộng làm việc giống ToList ngoại trừ nó tránh việc tạo toàn bộ danh sách.

Nguồn: http://www.entityframeworktutorial.net/

Advertisements