asp.net core系列 32 EF查询数据 必备知识(1)
一.查询的工作原理
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
});
参考文献
asp.net core系列 32 EF查询数据 必备知识(1)的更多相关文章
- asp.net core系列 33 EF查询数据 (2)
一. 原生SQL查询 接着上篇讲.通过 Entity Framework Core 可以在使用关系数据库时下降到原始 SQL 查询. 在无法使用 LINQ 表达要执行的查询时,或因使用 LINQ 查询 ...
- asp.net core系列 35 EF保存数据(2) -- EF系列结束
一.事务 (1) 事务接着上篇继续讲完.如果使用了多种数据访问技术,来访问关系型数据库,则可能希望在这些不同技术所执行的操作之间共享事务.下面示例显示了如何在同一事务中执行 ADO.NET SqlCl ...
- asp.net core系列 34 EF保存数据(1)
一. 基本数据 每个EF上下文实例都有一个 ChangeTracker(更改跟踪器),它负责跟踪需要写入数据库的更改. 当更改实体类的实例时(修改属性,删除实例,新建实例等),这些更改会记录在 Cha ...
- asp.net core系列 30 EF管理数据库架构--必备知识 迁移
一.管理数据库架构概述 EF Core 提供两种主要方法来保持 EF Core 模型和数据库架构同步.一是以 EF Core 模型为基准,二是以数据库为基准. (1)如果希望以 EF Core 模型为 ...
- asp.net core系列 31 EF管理数据库架构--必备知识 反向工程
一. 反向工程 反向工程是基于数据库架构,生成的实体类和DbContext类代码的过程,对于Visual Studio开发,建议使用PMC.对于其他开发环境,请选择.NET Core CLI工具( ...
- asp.net core 系列 22 EF(连接字符串,连接复原,DbContext)
一.连接字符串 在上二篇中,ASP.NET Core 应用程序连接字符串是写死在ConfigureServices代码中,下面介绍通过配置来实现.连接字符串可以存储在 appsettings.json ...
- asp.net core系列 29 EF模型配置(查询类型,关系数据库建模)
一.查询类型 此功能是EF Core 2.1中的新功能. EF Core除了实体类型之外,EF Core模型还可以包含查询类型,这些查询类型是针对“未映射到实体类型”的数据获取.比如视图,或只读数据表 ...
- asp.net core 系列 21 EF现有数据库进行反向工程
一.概述 在上篇中使用EF基于数据模型创建数据库, 本篇继续使用 EF 基于数据库创建数据模型. 实现对已有数据库进行反向工程,来构建数据访问的 ASP.NET Core MVC 应用程序.已有 ...
- asp.net core 系列 20 EF基于数据模型创建数据库
一.概述 本章使用 Entity Framework Core 构建执行基本数据访问的 ASP.NET Core MVC 应用程序.使用迁移(migrations)基于数据模型创建数据库,是一种cod ...
随机推荐
- symfony小练习-表白墙
过上一个博客系统以及对官方示例程序的基本学习,目前对symfony的各个组件有了一定的学习,学校布置了一个表白墙任务,这里就这个任务的完成进行记录 ...........2019.3.20.22.31 ...
- CMD运行命令每次都要进入很麻烦
20:35:52 win+r 输入regedit 进入注册表 找到HKEY_LOCAL_MACHINE\Software\Microsoft\Command Processor项 创建AutoRun ...
- docker“少折腾”
1.docker镜像加速 新版的 Docker 使用 /etc/docker/daemon.json(Linux) 或者 %programdata%\docker\config\daemon.json ...
- Shell脚本学习 - 基本内容以及数据格式
为了捞取日志,自己用python写了一些东西,大致套路就是读取写入文件的操作,放到linux上跑.实际使用时发现要操作的文件有时比较大,直接打开文件找需要的东西可能会有一些效率问题.所以学习一下she ...
- U-Boot内存管理
如<Linux内核内存管理架构>一文中提到,linux内核中的内存管理支持内存地址映射.内存分配.内存回收.内存碎片管理.页面缓存等众多功能.但U-Boot做为启动引导程序,其核心功能就是 ...
- [ubuntu]apt-get update突然出现arm package找不到
https://blog.csdn.net/l741299292/article/details/69671789
- 从Excel导数据到MySQL速度优化
运行环境: Windows10 和 Deepin15.7, MySQL14.4, Java1.8.0_181使用工具: poi,JDBC数据规模: 35万条,5个文件夹,146个Excel文件(.xl ...
- vijos搭建踩坑
nodejs我用的8.x版本,可以工作. 和制作组交谈之后他们说最好榨汁机和主机不要在同一系统下. vj4/vj4/handler/base.py的第343行 从 super(Connection, ...
- 上传插件webupload之调用拍照兼容问题
在项目中,移动端用到了webupload插件来实现上传功能(我觉得这个插件挺好用的,所以无论pc还是移动端我都使用了这个插件来做上传功能) 在移动端要调起拍照功能,实现上传,须得在webuploade ...
- CSS矩形、三角形等
1.圆形 CSS代码如下:宽高一样,border-radius设为宽高的一半 #circle { width: 100px; height: 100px; background: red; -moz- ...