Chúng ta đã tạo EDM, DbContext và những lớp thực thể trong những phần trước. Bạn sẽ học những kiểu truy vấn khác nhau mà Entity Framework, nó lần lượt chuyển đổi thành truy vấn SQL cho CSDL bên dưới.

Entity Framework hỗ trợ 3 kiểu truy vấn: LINQ to Entities, Entity SQL và Native SQL.

I. LINQ to Entities:

Language-Integrated Query (LINQ) là một ngôn ngữ truy vấn mạnh mẽ được giới thiệu trong VS 2008. Bạn có thể sử dụng LINQ trong C# hoặc Visual Basic để truy vấn những dữ liệu nguồn khác nhau. LINQ-to-Entities hoạt động trên những thực thể Entity Framework để truy cập dữ liệu từ CSDL bên dưới. Bạn có thể sử dụng cú pháp LINQ method hoặc cú pháp truy vấn khi truy vấn với EDM.

Cú pháp LINQ Method:

//Querying with LINQ to Entities 
using (var context = new SchoolDBEntities())
{
    var L2EQuery = context.Students.where(s => s.StudentName == "Bill");
        
    var student = L2EQuery.FirstOrDefault<Student>();

}

Cú pháp LINQ Query:

using (var context = new SchoolDBEntities())
{
    var L2EQuery = from st in context.Students
                    where st.StudentName == "Bill"
                    select st;
   
    var student = L2EQuery.FirstOrDefault<Student>();
    }

Đầu tiên bạn phải tạo một đối tượng của lớp context đó là SchoolDBEntities. Bạn nên khởi tạo nó ở using() để một khi nó bên ngoài phạm vi thì nó sẽ tự động gọi phương thức Dispose() của DbContext. Cả hai cú pháp trên, context đều trả về IQueryable.

Những truy vấn Linq-to-Entities Projection:

Projection là một quá trình lựa chọn dữ liệu trong một dạng khác hơn là một dạng thực thể cụ thể đang truy vấn. Có nhiều cách của projection. Chúng ta giờ sẽ nhìn thấy vài kiểu của projection:

First/FirstOrDefault:

Nếu bạn muốn lấy một đối tượng sinh viên đơn khi có nhiều sinh viên, tên của đối tượng đó là “Student1” trong CSDL thì bạn sử dụng First hoặc FirstOrDefault như bên dưới:

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

Câu truy vấn trên sẽ thành truy vấn CSDL như sau:

SELECT TOP (1) 
[Extent1].[StudentID] AS [StudentID], 
[Extent1].[StudentName] AS [StudentName], 
[Extent1].[StandardId] AS [StandardId]
FROM [dbo].[Student] AS [Extent1]
WHERE 'Student1' = [Extent1].[StudentName]

Khác nhau giữa First và FirstOrDefault là First() sẽ ném ra một exception nếu không có dữ liệu kết quả cho tiêu thức đã cung cấp trong khi FirstOrDefault() trả về giá trị mặc định (null) nếu không có dữ liệu kết quả.

Single/SingleOrDefault:

Bạn cũng có thể sử dụng Single hoặc SingleOrDefault để lấy một đối tượng sinh viên đơn như thể hiện bên dưới:

using (var ctx = new SchoolDBEntities())
{    
    var student = (from s in context.Students
                    where s.StudentID == 1
                    select s).SingleOrDefault<Student>();
}

Câu truy vấn trên sẽ thực thi truy vấn CSDL như sau:

SELECT TOP (2) 
[Extent1].[StudentID] AS [StudentID], 
[Extent1].[StudentName] AS [StudentName], 
[Extent1].[StandardId] AS [StandardId]
FROM [dbo].[Student] AS [Extent1]
WHERE 1 = [Extent1].[StudentID]
go

Single hoặc SingleOrDefault sẽ ném ra một exception nếu kết quả trả về có nhiều hơn một phần tử. Sử dụng Single hoặc SingleOrDefault nếu bạn chắn chắn rằng kết quả trả về sẽ có chỉ một phần tử. Nếu kết quả có nhiều phần tử thì sẽ có vài vấn đề.

ToList:

Nếu bạn muốn liệt kê tất cả những sinh viên với tên ‘Student1’ (nếu có nhiều sinh viên trùng tên) thì sử dụng ToList():

using (var ctx = new SchoolDBEntities())
{    
    var studentList = (from s in ctx.Students
    where s.StudentName == "Student1"
    select s).ToList<Student>();
}

Câu truy vấn trên sẽ thành truy vấn CSDL như sau:

SELECT 
[Extent1].[StudentID] AS [StudentID], 
[Extent1].[StudentName] AS [StudentName], 
[Extent1].[StandardId] AS [StandardId]
FROM [dbo].[Student] AS [Extent1]
WHERE 'Student1' = [Extent1].[StudentName]
go

GroupBy:

Nếu bạn muốn nhóm những sinh viên bằng StandardId thì sử dụng groupby:

using (var ctx = new SchoolDBEntities())
{    
    var students = from s in ctx.Students 
                   group s by  s.StandardId into studentsByStandard
                   select studentsByStandard;
}

Câu truy vấn trên sẽ thực thi truy vấn CSDL như sau:

SELECT 
[Project2].[C1] AS [C1], 
[Project2].[StandardId] AS [StandardId], 
[Project2].[C2] AS [C2], 
[Project2].[StudentID] AS [StudentID], 
[Project2].[StudentName] AS [StudentName], 
[Project2].[StandardId1] AS [StandardId1]
FROM ( SELECT 
    [Distinct1].[StandardId] AS [StandardId], 
    1 AS [C1], 
    [Extent2].[StudentID] AS [StudentID], 
    [Extent2].[StudentName] AS [StudentName], 
    [Extent2].[StandardId] AS [StandardId1], 
    CASE WHEN ([Extent2].[StudentID] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C2]
    FROM   (SELECT DISTINCT 
        [Extent1].[StandardId] AS [StandardId]
        FROM [dbo].[Student] AS [Extent1] ) AS [Distinct1]
    LEFT OUTER JOIN [dbo].[Student] AS [Extent2] ON ([Distinct1].[StandardId] = [Extent2].[StandardId]) OR (([Distinct1].[StandardId] IS NULL) AND ([Extent2].[StandardId] IS NULL))
)  AS [Project2]
ORDER BY [Project2].[StandardId] ASC, [Project2].[C2] ASC
go

OrderBy:

Nếu bạn muốn lấy danh sách của những sinh viên được sắp xếp theo StudentName thì sử dụng OrderBy:

using (var ctx = new SchoolDBEntities())
{    
        var student1 = from s in ctx.Students
                    orderby s.StudentName ascending
                    select s;
}

Câu truy vấn trên sẽ thực thi truy vấn CSDL như sau:

SELECT 
[Extent1].[StudentID] AS [StudentID], 
[Extent1].[StudentName] AS [StudentName], 
[Extent1].[StandardId] AS [StandardId]
FROM [dbo].[Student] AS [Extent1]
ORDER BY [Extent1].[StudentName] ASC
go

Anonymous Class result:

Nếu bạn muốn lấy chỉ StudentName, StandardName và danh sách của những khóa học trong một đối tượng đơn thì viết projection sau:

using (var ctx = new SchoolDBEntities())
{    
    var projectionResult = from s in ctx.Students
                        where s.StudentName == "Student1"
                        select new { 
                        s.StudentName, s.Standard.StandardName, s.Courses 
                        };
}

Câu truy vấn trên sẽ thực thi truy vấn CSDL như sau:

SELECT 
[Extent1].[StudentID] AS [StudentID], 
[Extent1].[StudentName] AS [StudentName], 
[Extent2].[City] AS [City]
FROM  [dbo].[Student] AS [Extent1]
LEFT OUTER JOIN [dbo].[StudentAddress] AS [Extent2] ON [Extent1].[StudentID] = [Extent2].[StudentID]
WHERE 1 = [Extent1].[StandardId]
go

ProjectionResult trong truy vấn trên sẽ là kiểu nặc danh bởi vì không có lớp hoặc thực thể nào có những thuộc tính đó. Vì vậy trình biên dịch sẽ đánh dấu nó như là nặc danh.

Những truy vấn nested:

Bạn cũng có thể thực thi những truy vấn nested  LINQ to entity như sau:

entity relationships in entity framework

Truy vấn nested thể hiện ở trên sẽ kết quả trong một danh sách nặc danh với một đối tượng StudentName và Course.

SELECT 
[Extent1].[StudentID] AS [StudentID], 
[Extent1].[StudentName] AS [StudentName], 
[Join1].[CourseId1] AS [CourseId], 
[Join1].[CourseName] AS [CourseName], 
[Join1].[Location] AS [Location], 
[Join1].[TeacherId] AS [TeacherId]
FROM  [dbo].[Student] AS [Extent1]
INNER JOIN  (SELECT [Extent2].[StudentId] AS [StudentId], [Extent3].[CourseId] AS [CourseId1], [Extent3].[CourseName] AS [CourseName], [Extent3].[Location] AS [Location], [Extent3].[TeacherId] AS [TeacherId]
    FROM  [dbo].[StudentCourse] AS [Extent2]
    INNER JOIN [dbo].[Course] AS [Extent3] ON [Extent3].[CourseId] = [Extent2].[CourseId] ) AS [Join1] ON [Extent1].[StudentID] = [Join1].[StudentId]
WHERE 1 = [Extent1].[StandardId]
go

Theo cách này bạn có thể làm một projection của kết quả. Theo cách bạn sẽ giống dữ liệu.

II. Entity SQL:

Entity SQL là cách khác để tạo một truy vấn. Nó được xử lý bởi Object Services của Entity Framework Object Services trực tiếp. Nó trả về ObjectQuery thay vì IQueryable.

Bạn cần ObjectContext để tạo một truy vấn sử dụng Entity SQL.

Đoạn mã sau thể hiện cùng một kết quả truy vấn như truy vấn L2E trên.

//Querying with Object Services and Entity SQL
string sqlString = "SELECT VALUE st FROM SchoolDBEntities.Students " +
                    "AS st WHERE st.StudentName == 'Bill'";
    
var objctx = (ctx as IObjectContextAdapter).ObjectContext;
                
ObjectQuery<Student> student = objctx.CreateQuery<Student>(sqlString);
                Student newStudent = student.First<Student>();

Bạn cũng có thể sử dụng EntityConnection và EntityCommand để thực thị Entity SQL như thể hiện bên dưới:

using (var con = new EntityConnection("name=SchoolDBEntities"))
{
    con.Open();
    EntityCommand cmd = con.CreateCommand();
    cmd.CommandText = "SELECT VALUE st FROM SchoolDBEntities.Students as st where st.StudentName='Bill'";
    Dictionary<int, string> dict = new Dictionary<int, string>();
    using (EntityDataReader rdr = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.CloseConnection))
    {
            while (rdr.Read())
            {
                int a = rdr.GetInt32(0);
                var b = rdr.GetString(1);
                dict.Add(a, b);
            }
    }               
}

EntityDataReader không trả về ObjectQuery. Thay vì đó nó trả về dữ liệu theo dòng và cột.

Native SQL:

Bạn có thể thực thi những truy vấn native SQL cho một CSDL quan hệ như sau:

using (var ctx = new SchoolDBEntities())
{
    var studentName = ctx.Students.SqlQuery("Select studentid, studentname, standardId from Student where studentname='Bill'").FirstOrDefault<Student>();
}

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

Advertisements