当前位置: 移动技术网 > IT编程>开发语言>.net > asp.net core系列 32 EF查询数据 必备知识(1)

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

2019年02月27日  | 移动技术网IT编程  | 我要评论

叛军领主的军械库,win10自动更新在哪,男女人体图片

一.查询的工作原理

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

 

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网