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 == 1);
    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() >1
                        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 == 1
                        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 == 1);
        blog.Rating = 5;
        context.SaveChanges();

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

    

  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查询数据

原文地址:https://www.cnblogs.com/MrHSR/p/10435921.html

时间: 2024-11-05 13:42:37

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

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

一.事务 (1) 事务接着上篇继续讲完.如果使用了多种数据访问技术,来访问关系型数据库,则可能希望在这些不同技术所执行的操作之间共享事务.下面示例显示了如何在同一事务中执行 ADO.NET SqlClient 操作和 Entity Framework Core 操作. using (var connection = new SqlConnection(connectionString)) { //使用ado.net 打开数据库连接 connection.Open(); //使用ado.net 开

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

原文:asp.net core 系列 22 EF(连接字符串,连接复原,DbContext) 一.连接字符串 在上二篇中,ASP.NET Core 应用程序连接字符串是写死在ConfigureServices代码中,下面介绍通过配置来实现.连接字符串可以存储在 appsettings.json.用户机密存储.其他配置源中. 下面示例演示appsettings.json 中存储的连接字符串,这样不管asp.net core在什么环境(Development.Staging .Production)

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

原文:asp.net core系列 30 EF管理数据库架构--必备知识 迁移 一.管理数据库架构概述 EF Core 提供两种主要方法来保持 EF Core 模型和数据库架构同步.一是以 EF Core 模型为基准,二是以数据库为基准. (1)如果希望以 EF Core 模型为准,请使用迁移. 对 EF Core 模型进行更改时,此方法会以增量方式将相应架构更改应用到数据库,以使数据库保持与 EF Core 模型兼容.  (2)如果希望以数据库架构为准,请使用反向工程. 使用此方法,可通过将数

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

原文:asp.net core 系列 20 EF基于数据模型创建数据库 一.概述 本章使用 Entity Framework Core 构建执行基本数据访问的 ASP.NET Core MVC 应用程序.使用迁移(migrations)基于数据模型创建数据库,是一种code first模式.可以在Windows 上使用 Visual Studio 2017,或在 Windows.macOS 或 Linux 上使用 .NET Core CLI 来学习.已经安装了NET Core 2.1 SDK,这

asp.net core系列 28 EF模型配置(字段,构造函数,拥有实体类型)

原文:asp.net core系列 28 EF模型配置(字段,构造函数,拥有实体类型) 一. 支持字段 EF允许读取或写入字段而不是一个属性.在使用实体类时,用面向对象的封装来限制或增强应用程序代码对数据访问的语义时,这可能很有用.无法使用数据注释配置.除了约定,还可以使用Fluent API为属性配置支持字段. 1.1 约定 public class Blog { // _<camel-cased property name> private string _url; public int

asp.net core系列 27 EF模型配置(索引,备用键,继承)

一.索引 索引是许多数据存储中的常见概念.虽然它们在数据存储中的实现可能会有所不同,但它们可用于更有效地基于列(或列集)进行查找.按照约定,用作外键每个属性 (或组的属性) 会自动创建索引.无法使用数据注释创建索引. 1.1 非唯一索引 Fluent API 在单个属性上指定索引.默认情况下,索引是非唯一的.如下代码示例在Blogs表上创建Url列索引: class MyContext : DbContext { public DbSet<Blog> Blogs { get; set; } p

asp.net core系列 36 WebAPI 搭建详细示例

原文:asp.net core系列 36 WebAPI 搭建详细示例 一.概述 HTTP不仅仅用于提供网页.HTTP也是构建公开服务和数据的API强大平台.HTTP简单灵活且无处不在.几乎任何你能想到的平台都有一个HTTP库,因此HTTP服务可以覆盖广泛的客户端,包括浏览器,移动设备和传统的桌面应用程序. ASP.NET Web API 是一个框架,基于.NET Framework 或.NET Core 之上构建 Web API. 从本章开始学习Web API系列时,先从一个示例开始,下面使用A

asp.net core系列 64 结合eShopOnWeb全面认识领域模型架构

原文:asp.net core系列 64 结合eShopOnWeb全面认识领域模型架构 一.项目分析 在上篇中介绍了什么是"干净架构",DDD符合了这种干净架构的特点,重点描述了DDD架构遵循的依赖倒置原则,使软件达到了低藕合.eShopOnWeb项目是学习DDD领域模型架构的一个很好案例,本篇继续分析该项目各层的职责功能,主要掌握ApplicationCore领域层内部的术语.成员职责. 1. web层介绍 eShopOnWeb项目与Equinox项目,双方在表现层方面对比,没有太大

ASP.NET CORE系列【五】webapi整理以及RESTful风格化

原文:ASP.NET CORE系列[五]webapi整理以及RESTful风格化 介绍 什么是RESTful?  这里不多做赘述,详情请百度! 哈哈,本来还想巴拉巴拉介绍一些webapi, RESTful的, 还是算了,咱们直接上干货!(原因是懒!哈哈) 使用 以前使用过mvc的人对webapi 应该都很熟悉,先看一段熟悉的代码 大伙发现了什么没?跟以往mvc大多数相同,但有些地方不同 ,我们来一起看看有何区别 1.首先SysUsersController上面有一段代码 [Produces("a