Entity Framework Core系列教程-6-查询数据

Entity Framework Core中的查询

Entity Framework Core中的查询与EF 6.x中的查询相同,但具有更优化的SQL查询,并且能够将C#/ VB.NET函数包含在LINQ到实体查询中。
Entity Framework Core 允许你在模型中使用导航属性来加载相关实体。 有三种常见的 O/RM 模式可用于加载关联数据:

  • Eager loading (预先加载): 表示从数据库中加载关联数据,作为初始查询的一部分。
  • Explicit loading(显式加载): 表示稍后从数据库中显式加载关联数据。
  • Lazy loading(延迟加载): 表示在访问导航属性时,从数据库中以透明方式加载关联数据。

访问LINQ-to-Entities一章,以了解有关Entity Framework中查询基础的更多信息。
在这里,您将学习Entity Framework Core中引入的查询新功能。

查询中的C#/ VB.NET函数

EF Core在LINQ-to-Entities中具有新功能,我们可以在查询中包含C#或VB.NET函数。这在EF 6中是不可能的。

private static void Main(string[] args)
{
    var context = new SchoolContext();
    var studentsWithSameName = context.Students
                                      .Where(s => s.FirstName == GetName())
                                      .ToList();
}

public static string GetName() {
    return "Bill";
}

在上面的L2E查询中,我们在Where子句中包含了GetName() C#函数。这将在数据库中执行以下查询:

exec sp_executesql N'SELECT [s].[StudentId], [s].[DoB], [s].[FirstName],
    [s].[GradeId], [s].[LastName], [s].[MiddleName]
FROM [Students] AS [s]
WHERE [s].[FirstName] = @__GetName_0',N'@__GetName_0 nvarchar(4000)',
    @__GetName_0=N'Bill'
Go

Eager Loading 预先加载

Entity Framework Core支持使用Include()扩展方法和投影查询来快速加载与EF 6相同的相关实体。除此之外,它还提供了ThenInclude()扩展方法来加载多个级别的相关实体。 (EF 6不支持ThenInclude()方法。)

Include:

与EF 6不同,我们可以在Include()方法中将lambda表达式指定为参数,以指定导航属性,如下所示。

var context = new SchoolContext();
var studentWithGrade = context.Students
                           .Where(s => s.FirstName == "Bill")
                           .Include(s => s.Grade)
                           .FirstOrDefault();

在上面的示例中,.Include(s => s.Grade)传递lambda表达式s => s.Grade,以指定引用属性,该属性将在单个SQL查询中与来自数据库的Student实体数据一起加载。上面的查询在数据库中执行以下SQL查询。

SELECT TOP(1) [s].[StudentId], [s].[DoB], [s].[FirstName], [s].[GradeId],[s].[LastName],
        [s].[MiddleName], [s.Grade].[GradeId], [s.Grade].[GradeName], [s.Grade].[Section]
FROM [Students] AS [s]
LEFT JOIN [Grades] AS [s.Grade] ON [s].[GradeId] = [s.Grade].[GradeId]
WHERE [s].[FirstName] = N'Bill'

我们还可以在Include()方法中将属性名称指定为字符串,与EF 6中相同。

var context = new SchoolContext();
var studentWithGrade = context.Students
                        .Where(s => s.FirstName == "Bill")
                        .Include("Grade")
                        .FirstOrDefault();

不建议使用上面的示例,因为如果属性名称拼写错误或不存在,则会抛出运行时异常。始终对lambda表达式使用Include()方法,以便可以在编译时检测到错误。

Include()扩展方法也可以在FromSql()方法之后使用,如下所示。

var context = new SchoolContext();
var studentWithGrade = context.Students
                        .FromSql("Select * from Students where FirstName ='Bill'")
                        .Include(s => s.Grade)
                        .FirstOrDefault();      

注意:DbSet.Find()方法之后不能使用Include()扩展方法。例如。在EF Core 2.0中无法使用context.Students.Find(1).Include()。在将来的版本中这可能是可能的。

多次使用Include()方法来加载同一实体的多个导航属性。例如,以下代码加载与Student的Grade和StudentCourses相关的实体。

var context = new SchoolContext();
var studentWithGrade = context.Students.Where(s => s.FirstName == "Bill")
                        .Include(s => s.Grade)
                        .Include(s => s.StudentCourses)
                        .FirstOrDefault();

上面的查询将在单个数据库往返中执行两个SQL查询。

SELECT TOP(1) [s].[StudentId], [s].[DoB], [s].[FirstName], [s].[GradeId], [s].[LastName],
        [s].[MiddleName], [s.Grade].[GradeId], [s.Grade].[GradeName], [s.Grade].[Section]
FROM [Students] AS [s]
LEFT JOIN [Grades] AS [s.Grade] ON [s].[GradeId] = [s.Grade].[GradeId]
WHERE [s].[FirstName] = N'Bill'
ORDER BY [s].[StudentId]
Go

SELECT [s.StudentCourses].[StudentId], [s.StudentCourses].[CourseId]
FROM [StudentCourses] AS [s.StudentCourses]
INNER JOIN (
    SELECT DISTINCT [t].*
    FROM (
        SELECT TOP(1) [s0].[StudentId]
        FROM [Students] AS [s0]
        LEFT JOIN [Grades] AS [s.Grade0] ON [s0].[GradeId] = [s.Grade0].[GradeId]
        WHERE [s0].[FirstName] = N'Bill'
        ORDER BY [s0].[StudentId]
    ) AS [t]
) AS [t0] ON [s.StudentCourses].[StudentId] = [t0].[StudentId]
ORDER BY [t0].[StudentId]
Go

ThenInclude

EF Core引入了新的ThenInclude()扩展方法,以加载多个级别的相关实体。考虑以下示例:

var context = new SchoolContext();
var student = context.Students.Where(s => s.FirstName == "Bill")
                        .Include(s => s.Grade)
                            .ThenInclude(g => g.Teachers)
                        .FirstOrDefault();

在上面的示例中,.Include(s => s.Grade)将加载Student实体的Grade导航属性。 .ThenInclude(g => g.Teachers)将加载Grade实体的Teacher集合属性。必须在Include方法之后调用ThenInclude方法。上面的代码将在数据库中执行以下SQL查询。

SELECT TOP(1) [s].[StudentId], [s].[DoB], [s].[FirstName], [s].[GradeId], [s].[LastName],
         [s].[MiddleName], [s.Grade].[GradeId], [s.Grade].[GradeName], [s.Grade].[Section]
FROM [Students] AS [s]
LEFT JOIN [Grades] AS [s.Grade] ON [s].[GradeId] = [s.Grade].[GradeId]
WHERE [s].[FirstName] = N'Bill'
ORDER BY [s.Grade].[GradeId]
Go

SELECT [s.Grade.Teachers].[TeacherId], [s.Grade.Teachers].[GradeId], [s.Grade.Teachers].[Name]
FROM [Teachers] AS [s.Grade.Teachers]
INNER JOIN (
    SELECT DISTINCT [t].*
    FROM (
        SELECT TOP(1) [s.Grade0].[GradeId]
        FROM [Students] AS [s0]
        LEFT JOIN [Grades] AS [s.Grade0] ON [s0].[GradeId] = [s.Grade0].[GradeId]
        WHERE [s0].[FirstName] = N'Bill'
        ORDER BY [s.Grade0].[GradeId]
    ) AS [t]
) AS [t0] ON [s.Grade.Teachers].[GradeId] = [t0].[GradeId]
ORDER BY [t0].[GradeId]
go

Projection Query(投影查询)

我们还可以通过使用投影查询而不是Include()或ThenInclude()方法来加载多个相关实体。以下示例演示了用于加载“学生”,“年级”和“教师”实体的投影查询。

var context = new SchoolContext();
var stud = context.Students.Where(s => s.FirstName == "Bill")
                        .Select(s => new
                        {
                            Student = s,
                            Grade = s.Grade,
                            GradeTeachers = s.Grade.Teachers
                        })
                        .FirstOrDefault();

在上面的示例中,.Select扩展方法用于在结果中包括Student, Grade and Teacher实体。这将执行与上述ThenInclude()方法相同的SQL查询。

关于延迟加载(Lazy Loading)和显式加载( Explicit Loading). EF Core 3.1 已经支持,原文为2.0版本已过时,可以参考官方文档:

参考: https://docs.microsoft.com/en-us/ef/core/querying/related-data

原文地址:https://www.cnblogs.com/AlexanderZhao/p/12289193.html

时间: 2024-12-11 01:01:11

Entity Framework Core系列教程-6-查询数据的相关文章

asp.net core系列 32 EF查询数据 必备知识(1)

一.查询的工作原理 Entity Framework Core 使用语言集成查询 (LINQ) 来查询数据库中的数据. 通过 LINQ 可使用 C#(或你选择的其他 .NET 语言)基于派生上下文和实体类编写强类型查询. LINQ 查询的表示形式会传递给数据库提供程序,进而转换为特定的数据库查询语言(例如,适用于关系数据库的 SQL). 1.1 查询的生命周期, 下面是每个查询所经历的过程概述: (1) LINQ 查询由 E F处理,用于生成已准备好的表示形式,由数据库提供程序处理.缓存结果,以

使用Visual Studio开发ASP.NET Core MVC and Entity Framework Core初学者教程

原文地址:https://docs.asp.net/en/latest/data/ef-mvc/intro.html The Contoso University sample web application demonstrates how to create ASP.NET Core 1.0 MVC web applications using Entity Framework Core 1.0 and Visual Studio 2015. Contoso University网络应用的案

Entity Framework Core系列之什么是Entity Framework Core

前言 Entity Framework Core (EF Core)是微软推荐的基于.NET Core framework的应用程序数据访问技术.它是轻量级,可扩展并且支持跨平台开发.EF Core是一种对象关系映射器(ORM).通过应用程序实体对象和关系数据库中的数据的映射,使得开发人员能够以面向对象的方式处理数据. 为什么使用ORM 大多数开发框架都包含库,这些库允许通过类似记录集的数据结构访问关系数据库中的数据.下面的代码示例演示了一个典型的场景,即数据从数据库中检索并存储在ADO.NET

Entity Framework Core系列之实战(ASP.NET Core MVC应用程序)

本示例演示在ASP.NET 应用程序中使用EF CORE创建数据库并对其做基本的增删改查操作.当然我们默认你的机器上已经安装了.NET CORE SDK以及合适的IDE.本例使用的是Visual Studio Code. 创建一个ASP.NET Core 应用程序 如果你电脑上安装了VS2015或者更高版本,就可以使用项目模板创建一个ASP.NET Core application,或者可以使用命令行工具创建项目.在本例中我们将在Visual Studio Code 中使用命令行工具: 第一步:

ASP.NET CORE系列【二】使用Entity Framework Core进行增删改查

原文:ASP.NET CORE系列[二]使用Entity Framework Core进行增删改查 介绍 EntityFrameworkCore EF core 是一个轻量级的,可扩展的EF的跨平台版本.对于EF而言 EF core 包含许多提升和新特性,同时 EF core 是一个全新的代码库,并不如 EF6 那么成熟和稳定.EF core 保持了和EF相似的开发体验,大多数顶级API都被保留了下来,所以,如果你用过EF6,那么上手EF core你会觉得非常轻松和熟悉,EF core 构建在一

ASP.NET Core 配置 Entity Framework Core - ASP.NET Core 基础教程 - 简单教程,简单编程

原文:ASP.NET Core 配置 Entity Framework Core - ASP.NET Core 基础教程 - 简单教程,简单编程 ASP.NET Core 配置 Entity Framework Core 上一章节学习完了视图,其实我们应该立即着手讲解模型的,但 ASP.NET Core MVC 中的模型和 Entity Framework 有相当大的关系,所以,在此之前,我们先来讲讲 Entity Framework Core 和如何配置它 本章中,我们将设置和配置我们的应用程

使用Entity Framework Core需要注意的一个全表查询问题

.NET Core 迁移工作如火如荼,今天在使用 Entity Frameowork Core(又名EF Core)时写了下面这样的 LINQ 查询表达式: .Where(u => u.Id == new Guid(userId)).FirstOrDefaultAsync(); 结果在 SQL Server Profiler 中发现竟然进行了全表查询. 之后将 new Guid(userId) 从表达式中移出,保存于一个局部变量中,使用这个局部变量进行查询,全表查询问题就解决了. var use

UWP开发之ORM实践:如何使用Entity Framework Core做SQLite数据持久层?

选择SQLite的理由 在做UWP开发的时候我们首选的本地数据库一般都是Sqlite,我以前也不知道为啥?后来仔细研究了一下也是有原因的: 1,微软做的UWP应用大部分也是用Sqlite.或者说是微软推荐使用Sqlite吧! 2,简单!就只有一个类库没有多余的参照什么的.不像其他数据库还得做复杂配置什么的麻烦! 3,不需要数据库服务,数据服务和客户都在同一个进程里面.如下图: 4,作为存储系统它只支持一个用户一个数据实体. 5,跨平台跨结构,这个好! Sqlite主要使用内容 如果想充分使用好S

ASP.NET CORE系列【六】Entity Framework Core 之数据库迁移

前言 最近打算用.NET Core写一份简单的后台系统,来练练手 然后又用到了Entity Framework Core 发现园子里有些文章讲得不是那么细节,对于新手小白来说,可能会有点懵. 特意整理了几个细节. 正文 数据迁移 首先EF CORE跟以前的EF6是有不同点的, 微软官网列出的不同点:https://docs.microsoft.com/zh-cn/ef/efcore-and-ef6/features 安装 EF 核心 NuGet 包 若要使用 EF 核心,请为你想要使用的数据库提