一.查询的工作原理

  Entity Framework Core 使用语言集成查询 (LINQ) 来查询数据库中的数据。 通过 LINQ 可使用 C#(或你选择的其他 .NET 语言)基于派生上下文和实体类编写强类型查询。 LINQ 查询的表示形式会传递给数据库提供程序,进而转换为特定的数据库查询语言(例如,适用于关系数据库的 SQL)。

  1.1 查询的生命周期, 下面是每个查询所经历的过程概述:

    (1) LINQ 查询由 E F处理,用于生成已准备好的表示形式,由数据库提供程序处理。缓存结果,以便每次执行查询时都不需要执行此处理。

    (2) 结果将传递给数据库提供程序

      a.数据库提供程序会识别出查询的哪些部分可以在数据库中求值。

      b. 查询的这些部分会转换为特定数据库的查询语言(例如,关系数据库的 SQL)

      c. 将一个或多个查询发送到数据库并返回结果集(结果是来自数据库的值,而不是实体实例)

    (3) 返回结果集处理

      a.如果这是跟踪查询,EF会检查数据是否代表一个实体,已存在于上下文实例的更改跟踪器中。

        如果是,则会返回现有实体

        如果不是,则会创建新实体、设置更改跟踪并返回该新实体

      b.如果这是非跟踪查询,EF 会检查数据是否表示此查询结果集中的现有实体

        如果是,则会返回现有实体

        如果不是,则会创建新实体并返回该新实体

  1.2 执行查询时:

    调用LINQ运算符时,只会构建查询在内存中的表示形式。 只有在使用结果时,查询才会发送到数据库。触发查询发送到数据库的最常见操作如下:

    (1) 在 for 循环中循环访问结果

         var blogs = from b in BloggingContext.Blogs
select {....} //触发数据库查询
foreach (var item in blogs)
{
int maxID = item.ID;
}

    (2) 使用 ToList、ToArray、Single、Count 等操作都会触发数据库查询

        BloggingContext.Blogs.ToList();
BloggingContext.Blogs.ToArray();
BloggingContext.Blogs.Count();
BloggingContext.Blogs.Single();
BloggingContext.Blogs.First();

    (3) 将查询结果数据绑定到 UI

二.LINQ 查询

  Entity Framework Core 使用语言集成查询 (LINQ) 来查询数据库中的数据。 通过 LINQ 可使用 C#(或你选择的其他 .NET 语言)基于派生上下文和实体类编写强类型查询。 LINQ 查询的表示形式会传递给数据库提供程序,进而转换为特定的数据库查询语言(例如,适用于关系数据库的 SQL)。

    // (1)加载所有数据
var blogs = BloggingContext.Blogs.ToList();
    SELECT [b].[BlogId], [b].[Name], [b].[Title], [b].[Url] FROM [Blogs] AS [b]
    //(2)加载单个实体
var blog = BloggingContext.Blogs.Single(b => b.BlogId == );
    SELECT TOP(2) [b].[BlogId], [b].[Name], [b].[Title], [b].[Url]
FROM [Blogs] AS [b]
WHERE [b].[BlogId] = 1
    //(3)筛选
var blogs = BloggingContext.Blogs.Where(b => b.Url.Contains("dotnet")).ToList();
    SELECT [b].[BlogId], [b].[Name], [b].[Title], [b].[Url]
  FROM [Blogs] AS [b]
  WHERE CHARINDEX(N'dotnet', [b].[Url]) > 0

    

    //(4)排序
  var blogs = BloggingContext.Blogs.OrderByDescending(b => b.BlogId).Select(b=> new { b.BlogId,b.Name }).ToList();
  SELECT [b].[BlogId], [b].[Name]
  FROM [Blogs] AS [b]
  ORDER BY [b].[BlogId] DESC
    //(5) group  找出重复的url,取出最大BlogId
  var blogs = from b in BloggingContext.Blogs
group b by new { b.Url} into gs
where gs.Count() >
select new
{
ID= gs.Max(b=>b.BlogId)
};
   //top 1
   int maxID = blogs.First().ID;
    SELECT TOP(1) MAX([b].[BlogId]) AS [ID]
    FROM [Blogs] AS [b]
    GROUP BY [b].[Url]
    HAVING COUNT(*) > 1
      // (6)多表join查询
  var query = from b in context.Blogs
join p in context.Posts on b.BlogId equals p.BlogId
where b.BlogId ==
select new { b.Name,p.Title } ;
   var bloglinq= query.ToList();
    SELECT [b].[Name], [p].[Title]
    FROM [Blogs] AS [b]
    INNER JOIN [Posts] AS [p] ON [b].[BlogId] = [p].[BlogId]
    WHERE [b].[BlogId] = 1

      有关显示 LINQ 可完成的任务的大量示例,请参阅 101 个 LINQ 示例

三. 客户端求值

  EF支持部分查询在客户端上求值,而将其他部分推送到数据库执行。 由数据库提供程序确定查询的哪些部分会在数据库中求值。 下面示例中 客户端通过执行StandardizeUrl方法来返回 URL,查询的其余部分都是在数据库中执行的。

    var blogs = context.Blogs
.OrderByDescending(blog => blog.Rating)
.Select(blog => new
{
Id = blog.BlogId,
Url = StandardizeUrl(blog.Url)
})
.ToList();

public static string StandardizeUrl(string url)
{
url = url.ToLower(); if (!url.StartsWith("http://"))
{
url = string.Concat("http://", url);
} return url;
}

  

  3.1 可能的性能问题

    虽然客户端求值非常有用,但在某些情况下可能会导致性能不佳。 请考虑以下查询,该where中使用辅助方法。 由于无法在数据库中执行此操作,因此blog的所有数据将被拉入内存中,然后会在客户端上应用筛选器。 根据数据量以及过滤掉多少数据,可能会导致性能下降。

    var blogs = context.Blogs
.Where(blog => StandardizeUrl(blog.Url).Contains("dotnet"))
.ToList();

  3.2 为客户端评估抛出异常

    默认情况下,当执行客户端求值时,EF Core 将记录警告在日志中。可以改为引发异常或不执行任何操作。 设置如下所示

       services.AddDbContext<BloggingContext>
(options =>
options.UseSqlServer(connection)
//改为引发异常
.ConfigureWarnings(warnings => warnings.Throw(RelationalEventId.QueryClientEvaluationWarning))
);

四. 跟踪与非跟踪查询

  跟踪行为可控制 EF是否将有关实体实例的信息保留在其更改跟踪器中。 如果已跟踪某个实体,则该实体中检测到的任何更改都会在 SaveChanges() 期间永久保存到数据库。 EF 还会修正从跟踪查询中获取的实体与先前已加载到 DbContext 实例中的实体两者之间的导航属性。

   4.1 跟踪查询

    默认情况下,会跟踪返回实体类型的查询。 这表示可以更改这些实体实例,然后通过 SaveChanges() 持久化这些更改。在以下示例中,将检测到对Blog评分所做的更改,并在 SaveChanges() 期间将这些更改持久化到数据库中。

        var blog = context.Blogs.SingleOrDefault(b => b.BlogId == );
blog.Rating = ;
context.SaveChanges(); //显示设置与上面一样,开启了跟踪查询
var blog = context.Blogs. AsTracking().SingleOrDefault(b => b.BlogId == );

    

  4.2 非跟踪查询

    只需要读取数据结果方案时,非跟踪查询十分有用。 可以更快速地执行非跟踪查询,因为无需设置更改跟踪信息。

    //设置当前查询为非跟踪查询
var blogs = context.Blogs
.AsNoTracking()
.ToList();
//还可以在上下文实例级别, 设置默认为非跟踪查询
using (var context = new BloggingContext())
{
context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking; var blogs = context.Blogs.ToList();
}

   4.3跟踪和投影

    即使查询的结果类型不是实体类型,只要结果包含实体类型,则默认情况下也会跟踪这些实体类型。 在以下返回匿名类型的查询中,会跟踪结果集中 Blog 的实例。

    var blog = context.Blogs
.Select(b =>
new
{
Blog = b,
Posts = b.Posts.Count()
});

    如果结果集不包含任何实体类型,则不会执行跟踪。 在以下返回匿名类型(具有实体中的某些值,但没有实际实体类型的实例)的查询中,不会执行跟踪。

      var blog = context.Blogs
.Select(b =>
new
{
Id = b.BlogId,
Url = b.Url
});

参考文献

  EF查询数据

asp.net core系列 32 EF查询数据 必备知识(1)的更多相关文章

  1. asp.net core系列 33 EF查询数据 (2)

    一. 原生SQL查询 接着上篇讲.通过 Entity Framework Core 可以在使用关系数据库时下降到原始 SQL 查询. 在无法使用 LINQ 表达要执行的查询时,或因使用 LINQ 查询 ...

  2. asp.net core系列 35 EF保存数据(2) -- EF系列结束

    一.事务 (1) 事务接着上篇继续讲完.如果使用了多种数据访问技术,来访问关系型数据库,则可能希望在这些不同技术所执行的操作之间共享事务.下面示例显示了如何在同一事务中执行 ADO.NET SqlCl ...

  3. asp.net core系列 34 EF保存数据(1)

    一. 基本数据 每个EF上下文实例都有一个 ChangeTracker(更改跟踪器),它负责跟踪需要写入数据库的更改. 当更改实体类的实例时(修改属性,删除实例,新建实例等),这些更改会记录在 Cha ...

  4. asp.net core系列 30 EF管理数据库架构--必备知识 迁移

    一.管理数据库架构概述 EF Core 提供两种主要方法来保持 EF Core 模型和数据库架构同步.一是以 EF Core 模型为基准,二是以数据库为基准. (1)如果希望以 EF Core 模型为 ...

  5. asp.net core系列 31 EF管理数据库架构--必备知识 反向工程

    一.   反向工程 反向工程是基于数据库架构,生成的实体类和DbContext类代码的过程,对于Visual Studio开发,建议使用PMC.对于其他开发环境,请选择.NET Core CLI工具( ...

  6. asp.net core 系列 22 EF(连接字符串,连接复原,DbContext)

    一.连接字符串 在上二篇中,ASP.NET Core 应用程序连接字符串是写死在ConfigureServices代码中,下面介绍通过配置来实现.连接字符串可以存储在 appsettings.json ...

  7. asp.net core系列 29 EF模型配置(查询类型,关系数据库建模)

    一.查询类型 此功能是EF Core 2.1中的新功能. EF Core除了实体类型之外,EF Core模型还可以包含查询类型,这些查询类型是针对“未映射到实体类型”的数据获取.比如视图,或只读数据表 ...

  8. asp.net core 系列 21 EF现有数据库进行反向工程

    一.概述 在上篇中使用EF基于数据模型创建数据库,  本篇继续使用 EF  基于数据库创建数据模型.  实现对已有数据库进行反向工程,来构建数据访问的 ASP.NET Core MVC 应用程序.已有 ...

  9. asp.net core 系列 20 EF基于数据模型创建数据库

    一.概述 本章使用 Entity Framework Core 构建执行基本数据访问的 ASP.NET Core MVC 应用程序.使用迁移(migrations)基于数据模型创建数据库,是一种cod ...

随机推荐

  1. symfony小练习-表白墙

    过上一个博客系统以及对官方示例程序的基本学习,目前对symfony的各个组件有了一定的学习,学校布置了一个表白墙任务,这里就这个任务的完成进行记录 ...........2019.3.20.22.31 ...

  2. CMD运行命令每次都要进入很麻烦

    20:35:52 win+r  输入regedit 进入注册表 找到HKEY_LOCAL_MACHINE\Software\Microsoft\Command Processor项 创建AutoRun ...

  3. docker“少折腾”

    1.docker镜像加速 新版的 Docker 使用 /etc/docker/daemon.json(Linux) 或者 %programdata%\docker\config\daemon.json ...

  4. Shell脚本学习 - 基本内容以及数据格式

    为了捞取日志,自己用python写了一些东西,大致套路就是读取写入文件的操作,放到linux上跑.实际使用时发现要操作的文件有时比较大,直接打开文件找需要的东西可能会有一些效率问题.所以学习一下she ...

  5. U-Boot内存管理

    如<Linux内核内存管理架构>一文中提到,linux内核中的内存管理支持内存地址映射.内存分配.内存回收.内存碎片管理.页面缓存等众多功能.但U-Boot做为启动引导程序,其核心功能就是 ...

  6. [ubuntu]apt-get update突然出现arm package找不到

    https://blog.csdn.net/l741299292/article/details/69671789

  7. 从Excel导数据到MySQL速度优化

    运行环境: Windows10 和 Deepin15.7, MySQL14.4, Java1.8.0_181使用工具: poi,JDBC数据规模: 35万条,5个文件夹,146个Excel文件(.xl ...

  8. vijos搭建踩坑

    nodejs我用的8.x版本,可以工作. 和制作组交谈之后他们说最好榨汁机和主机不要在同一系统下. vj4/vj4/handler/base.py的第343行 从 super(Connection, ...

  9. 上传插件webupload之调用拍照兼容问题

    在项目中,移动端用到了webupload插件来实现上传功能(我觉得这个插件挺好用的,所以无论pc还是移动端我都使用了这个插件来做上传功能) 在移动端要调起拍照功能,实现上传,须得在webuploade ...

  10. CSS矩形、三角形等

    1.圆形 CSS代码如下:宽高一样,border-radius设为宽高的一半 #circle { width: 100px; height: 100px; background: red; -moz- ...