EF 6 DB-First系列--Entity Framework中的查询--Linq-to-Entities查询

Linq-to-Entities查询

Entity Framework支持三种类型的查询:1) LINQ-to-Entities, 2) Entity SQL, and 3) Native SQL

在这里,您将学习如何编写linq到实体的查询,并在Entity Framework 6.x 中获得结果,同样也适用于 Entity Framework Core。

DbSet类派生自IQuerayable。因此,我们可以使用LINQ对DbSet进行查询,这将会被转换为SQL查询。EF API对底层数据库执行此SQL查询,以获得结果集,然后将其转换为适当的实体对象并将其作为查询结果返回。

下面是一些可用于linq到实体查询的标准查询操作符(或扩展方法)。

LINQ扩展方法:
First()
FirstOrDefault()
Single()
SingleOrDefault()
ToList()
Count()
Min()
Max()
Last()
LastOrDefault()
Average()

Find()

除了LINQ扩展方法,我们还可以使用DbSet的Find()方法根据主键值搜索实体。

我们假设SchoolDbEntities是我们的DbContext类,Students是DbSet属性。

var ctx = new SchoolDBEntities();

var student = ctx.Students.Find(1);

在上面的例子中,ctx.Student.Find(1)在数据库中返回一个studententid为1的学生记录。如果没有找到记录,则返回null。上面的查询将执行以下SQL查询。

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=1go

First/FirstOrDefault

如果你想获得一个学生对象,当数据库中有很多学生,他们的名字是“Bill”,然后使用First或FirstOrDefault,如下所示:

LINQ查询语法:

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

LINQ方法语法:

using (var ctx = new SchoolDBEntities())
{    
    var student = ctx.Students.Where(s => s.StudentName == "Bill")
                              .FirstOrDefault<Student>();
}

EF 6在数据库中为上面的LINQ查询执行以下SQL查询。

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

EF Core在数据库中执行以下查询。

SELECT TOP (1) 
[s].[StudentId], [s].[DoB], [s].[FirstName], [s].[GradeId], 
[s].[LastName], [s].[MiddleName]
FROM [Students] AS [s]
WHERE [s].[FirstName] = N'Bill'

参数化查询

如果LINQ-to-Entities查询使用参数,EF将在数据库中构建并执行参数化查询,如下所示。

using (var ctx = new SchoolDBEntities())
{    
    string name = "Bill";
    var student = ctx.Students
                  .Where(s => s.StudentName == name)
                  .FirstOrDefault<Student>();
}

在EF 6中,上述查询将导致以下SQL查询。

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'

First和FirstOrDefault之间的区别是,如果提供的条件没有结果数据,First()将抛出异常,而FirstOrDefault()如果没有结果数据,则返回默认值(null)。

ToList

ToList方法返回收集结果。如果你想列出所有同名的学生,那么使用ToList():

using (var ctx = new SchoolDBEntities())
{    
    var studentList = ctx.Students.Where(s => s.StudentName == "Bill").ToList();
}

我们也可以使用ToArray, ToDictionary或ToLookup。上述查询将导致以下数据库查询:

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

GroupBy

使用group by操作符或GroupBy扩展方法可根据实体的特定属性获得基于group by的结果。

下面的示例根据每个Standard获得分组的结果。使用foreach循环迭代组。

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);
        }
    }
}

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);
        }
    }
}

上面的查询将执行以下数据库查询:

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

在LINQ查询语法中使用带有升序/降序关键字的OrderBy操作符来获得排序的实体列表。

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

使用OrderBy或OrderbyDescent方法获取排序的实体列表。

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();
}

上面的查询将执行以下数据库查询:

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

匿名对象结果

LINQ-to-Entities查询并不总是必须返回实体对象。因此,我们可以选择实体的某些属性。

下面的查询返回一个匿名对象列表,其中包含studententid和StudentName属性。

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);
    }
}

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);
    }
}

上面的查询将执行以下数据库查询:

SELECT 
[s].[StudentID] AS [Id], [s].[StudentName] AS [Name]
FROM [Student] AS [s]
WHERE [s].[StandardId] = 1
go

上述查询中的projectionResult将是匿名类型,因为没有具有这些属性的类/实体。因此,编译器会将其标记为匿名。

嵌套查询

你也可以执行嵌套的linq到实体的查询,如下所示:
在这里插入图片描述
上面所示的嵌套查询将产生一个具有StudentName和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

通过这种方式,您可以根据需要的数据对结果进行投影。

参考

https://www.entityframeworktutorial.net/
https://msdn.microsoft.com/

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值