LINQ-to-Entities trong Entity Framework
Lớp DbSet
có nguồn gốc từ interface IQuerayable
. Vì vậy, chúng ta có thể sử dụng LINQ để truy vấn DbSet
và những truy vấn này sẽ được chuyển đổi thành truy vấn SQL.
Entity Framework API thực thi truy vấn SQL này vào cơ sở dữ liệu, lấy danh sách kết quả trả về, chuyển đổi nó thành các đối tượng thực thể phù hợp và trả về nó dưới dạng kết quả truy vấn.
Sau đây là một số phương thức mở rộng có thể được sử dụng với các truy vấn LINQ-to-Entities.
Phương thức mở rộng của LINQ |
---|
First() |
FirstOrDefault() |
Single() |
SingleOrDefault() |
ToList() |
Count() |
Min() |
Max() |
Last() |
LastOrDefault() |
Average() |
Phương thức Find()
Ngoài các phương thức mở rộng LINQ, chúng ta có thể sử dụng phương thức Find()
của DbSet
để tìm kiếm thực thể dựa trên giá trị khóa chính.
Chúng ta sẽ sử dụng SchoolDbEntities
ở các chương trước là lớp DbContext
và nó có thuộc tính Students
là một thuộc tính DbSet
.
var ctx = new SchoolDBEntities();
var student = ctx.Students.Find(1);
Trong ví dụ trên, phương thức ctx.Student.Find(1)
trả về thông tin của một sinh viên có StudentId là 1 trong cơ sở dữ liệu. Nếu không có bản ghi nào được tìm thấy, thì nó trả về null. Truy vấn trên sẽ thực hiện truy vấn SQL sau.
SELECT
[Extent1].[StudentID] AS [StudentID],
[Extent1].[StudentName] AS [StudentName],
[Extent1].[StandardId] AS [StandardId]
FROM [dbo].[Student] AS [Extent1]
WHERE [Extent1].[StudentId] = @p0',N'@p0 int',@p0=1
go
Phương thức First() / FirstOrDefault()
Nếu bạn muốn lấy một đối tượng sinh viên trong những sinh viên có tên là “Bill” trong cơ sở dữ liệu, thì hãy sử dụng phương thức First
hoặc FirstOrDefault
, như ví dụ bên dưới:
Cú pháp truy vấn LINQ:
using (var ctx = new SchoolDBEntities())
{
var student = (from s in ctx.Students
where s.StudentName == "Bill"
select s).FirstOrDefault<Student>();
}
Cú pháp phương thức LINQ:
using (var ctx = new SchoolDBEntities())
{
var student = ctx.Students
.Where(s => s.StudentName == "Bill")
.FirstOrDefault<Student>();
}
EF 6 thực hiện truy vấn SQL sau trong cơ sở dữ liệu cho truy vấn LINQ ở trên.
SELECT TOP (1)
[Extent1].[StudentID] AS [StudentID],
[Extent1].[StudentName] AS [StudentName],
[Extent1].[StandardId] AS [StandardId]
FROM [dbo].[Student] AS [Extent1]
WHERE 'Bill' = [Extent1].[StudentName]
Tip: bạn nên sử dụng phương thức FirstOrDefault thay cho phương thức First. Lý do là vì phương thức First sẽ ném ra ngoại lệ nếu truy vấn không có dữ liệu còn phương thức FirstOrDefault sẽ trả về null trong trường hợp này.
Truy vấn có tham số
Entity Framework (EF) xây dựng và thực thi một truy vấn có tham số trong cơ sở dữ liệu nếu truy vấn LINQ-to-Entities sử dụng các tham số, chẳng hạn như ví dụ bên dưới.
using (var ctx = new SchoolDBEntities())
{
string name = "Bill";
var student = ctx.Students
.Where(s => s.StudentName == name)
.FirstOrDefault<Student>();
}
Truy vấn trên sẽ dẫn đến truy vấn SQL sau trong Entity Framework (EF) 6.
SELECT TOP (1)
[Extent1].[StudentId] AS [StudentId],
[Extent1].[Name] AS [Name]
FROM [dbo].[Student] AS [Extent1]
WHERE ([Extent1].[Name] = @p__linq__0) OR (([Extent1].[Name] IS NULL)
AND (@p__linq__0 IS NULL))',N'@p__linq__0 nvarchar(4000)',@p__linq__0=N'Bill'
Phương thức ToList()
Phương thức ToList
trả về danh sách kết quả. Nếu bạn muốn liệt kê tất cả các sinh viên có cùng tên “Bill” thì hãy sử dụng phương thức ToList()
:
using (var ctx = new SchoolDBEntities())
{
var studentList = ctx.Students.Where(s => s.StudentName == "Bill").ToList();
}
Chúng ta cũng có thể sử dụng phương thức ToArray()
, ToDictionary()
hoặc ToLookup()
để trả về danh sách kết quả. Truy vấn trên sẽ dẫn đến truy vấn SQL trong cơ sở dữ liệu như sau:
SELECT
[Extent1].[StudentID] AS [StudentID],
[Extent1].[StudentName] AS [StudentName],
[Extent1].[StandardId] AS [StandardId]
FROM [dbo].[Student] AS [Extent1]
WHERE 'Bill' = [Extent1].[StudentName]
go
Phương thức GroupBy()
Sử dụng toán tử group by
hoặc phương thức mở rộng GroupBy
để lấy kết quả được nhóm theo thuộc tính cụ thể của một thực thể.
Ví dụ sau đây nhận được các kết quả được nhóm theo thuộc tính StandardId
của thực thể Student
. Sử dụng vòng lặp foreach để duyệt các phần tử trong nhóm như ví dụ dưới đây.
Cú pháp truy vấn LINQ:
using (var ctx = new SchoolDBEntities())
{
var students = from s in ctx.Students
group s by s.StandardId into studentsByStandard
select studentsByStandard;
foreach (var groupItem in students)
{
Console.WriteLine(groupItem.Key);
foreach (var stud in groupItem)
{
Console.WriteLine(stud.StudentId);
}
}
}
Cú pháp phương thức LINQ:
using (var ctx = new SchoolDBEntities())
{
var students = ctx.Students.GroupBy(s => s.StandardId);
foreach (var groupItem in students)
{
Console.WriteLine(groupItem.Key);
foreach (var stud in groupItem)
{
Console.WriteLine(stud.StudentId);
}
}
}
Truy vấn trên sẽ thực hiện truy vấn SQL trong cơ sở dữ liệu 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
Phương thức OrderBy()
Sử dụng toán tử order by
với các từ khóa ascending
(sắp xếp tăng dần) hoặc descending
(sắp xếp giảm dần) trong cú pháp truy vấn LINQ để lấy danh sách thực thể được sắp xếp.
using (var ctx = new SchoolDBEntities())
{
var students = from s in ctx.Students
orderby s.StudentName ascending
select s;
}
Sử dụng phương thức OrderBy
(sắp xếp tăng dần) hoặc OrderByDescending
(sắp xếp giảm dần) để có được danh sách thực thể được sắp xếp.
using (var ctx = new SchoolDBEntities())
{
var students = ctx.Students.OrderBy(s => s.StudentName).ToList();
// or descending order
var descStudents = ctx.Students.OrderByDescending(s => s.StudentName).ToList();
}
Truy vấn trên sẽ thực hiện truy vấn SQL trong cơ sở dữ liệu 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
Trả về anonymous object
Các truy vấn LINQ-to-Entities không phải luôn trả về các đối tượng thực thể. Chúng ta có thể chọn một số thuộc tính của một thực thể để trả về kết quả.
Truy vấn sau đây trả về một danh sách các đối tượng ẩn danh (anonymous object) có chứa các thuộc tính StudentId
và StudentName
.
Cú pháp truy vấn LINQ:
using (var ctx = new SchoolDBEntities())
{
var anonymousObjResult = from s in ctx.Students
where s.StandardId == 1
select new
{
Id = st.StudentId,
Name = st.StudentName
};
foreach (var obj in anonymousObjResult)
{
Console.Write(obj.Name);
}
}
Cú pháp phương thức LINQ:
using (var ctx = new SchoolDBEntities())
{
var anonymousObjResult = ctx.Students
.Where(st => st.Standard == 1)
.Select(st => new
{
Id = st.StudentId,
Name = st.StudentName
});
foreach (var obj in anonymousObjResult)
{
Console.Write(obj.Name);
}
}
Truy vấn trên sẽ thực hiện truy vấn SQL trong cơ sở dữ liệu như sau:
SELECT
[s].[StudentID] AS [Id], [s].[StudentName] AS [Name]
FROM [Student] AS [s]
WHERE [s].[StandardId] = 1
go
Các truy vấn lồng nhau
Bạn cũng có thể thực hiện các truy vấn LINQ-to-Entities lồng nhau như dưới đây:
Truy vấn lồng nhau được trình bày ở trên sẽ trả về một danh sách các đối tượng ẩn danh có chứa các thuộc tính 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ể trả về bất kỳ dữ liệu gì mà bạn mong muốn.