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

一. 原生SQL查询

         接着上篇讲。通过 Entity Framework Core 可以在使用关系数据库时下降到原始 SQL 查询。 在无法使用 LINQ 表达要执行的查询时,或因使用 LINQ 查询而导致低效的 SQL 查询时非常有用。 原始 SQL 查询可返回实体类型,或者从 EF Core 2.1 开始,可返回模型中的查询类型。

  

  1.1 基本的原始SQL查询

    可以使用FromSql扩展方法,基于原始的SQL查询,开始LINQ查询。

        var blogs = context.Blogs
            .FromSql("SELECT * FROM dbo.Blogs")
            .ToList();
        --通过sql server profiler监听的sql,如下所示:
        select * from dbo.blogs

  1.2 原生 SQL 查询可用于执行存储过程(GetMostPopularBlogs)

    var blogs = context.Blogs
        .FromSql("EXECUTE dbo.GetMostPopularBlogs")
        .ToList();

  1.3 传递参数

    在使用FromSql执行原始sql查询时,传递参数要防止SQL注入攻击,可以在SQL查询字符串中包含参数占位符,然后提供参数值作为附加参数。任何参数值将自动转换为DbParameter来防止SQL注入

       var id = 4;
       var blgos=  BloggingContext.Blogs.FromSql("select * from dbo.blogs where BlogId={0}",id).ToList();
        --通过sql server profiler监听的sql,如下所示:
        exec sp_executesql N'select * from dbo.blogs where BlogId=@p0',N'@p0 int',@p0=4

    可以构造 DbParameter 并将其作为参数值提供。 这样可以在 SQL 查询字符串中使用命名参数(与上面占位符实现一样,只不过这里显示提供了命名参数@BlogId)。

       var user = new SqlParameter("@BlogId", 4);
       var blgos=  BloggingContext.Blogs.FromSql("select * from dbo.blogs where BlogId={0}", user).ToList();
        --通过sql server profiler监听的sql,如下所示:
        exec sp_executesql N'select * from dbo.blogs where BlogId=@BlogId',N'@BlogId int',@BlogId=4

    

  1.4 使用 LINQ 编写

    发送到数据库中的 SQL 查询可以是组合的,则可以在原始 SQL 查询后面紧跟着使用 LINQ 运算符。  SELECT 关键字开始的 SQL 查询一般是可组合的以下示例使用原始SQL查询,然后使用LINQ对其进行编写以执行过滤和排序。

          var blgos=  BloggingContext.Blogs
                .FromSql("select  blogid,url from dbo.blogs")
                .Where(b=>b.BlogId>2)
                .OrderByDescending(b=>b.BlogId)
                 .Select(b=> new{ b.BlogId, b.Url})
                .ToList();
       --通过sql server profiler监听的sql,原始sql成了一个子查询,如下所示:
    SELECT [b].[BlogId], [b].[Url]
    FROM (
        select  blogid,url from dbo.blogs
    ) AS [b]
    WHERE [b].[BlogId] > 2
    ORDER BY [b].[BlogId] DESC

二. 异步查询

  当在数据库中执行查询时,异步查询可避免阻止线程。 这有助于避免冻结富客户端应用程序的 UI。 异步操作还可以增加 Web 应用程序的吞吐量,可以在等数据库操作完成时(I/O),释放当前线程到线程池,该线程可去处理其他请求。

  注意: EF Core 不支持在同一上下文实例上运行多个并行操作。 应始终等待操作完成,然后再开始下一个操作。 这通常是通过在每个异步操作上使用 await 关键字完成的。

  Entity Framework Core 提供了一组异步扩展方法,可用作执行查询并返回结果的 LINQ 方法的替代方法。示例包括 ToListAsync()ToArrayAsync()SingleAsync() 等。对于部分 LINQ 运算符(如 Where(...)OrderBy(...) 等),没有对应的异步版本,因为这些方法仅用于构建 LINQ 表达式树,而未将查询发送到数据库中执行。

  下面是一个示例,注意async必须搭配await,只有await完成后才会释放当前EF上下文, async后面必须是Task(无返回值)或Task<T>(有返回值):

    public async Task<List<Blog>> GetBlogsAsync()
    {return await context.Blogs.ToListAsync();
    }

  

三. 全局查询筛选器

  全局查询筛选器是应用于元数据模型(通常为 OnModelCreating)中的实体类型的 LINQ 查询谓词(通常传递给 LINQ Where 查询运算符的布尔表达式)。

  下面使用 HasQueryFilter API 在 OnModelCreating 中配置查询筛选器。

      protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            //IsDeleted==1 没有被逻辑删除的Blog数据
            modelBuilder.Entity<Blog>().HasQueryFilter(b=>b.IsDeleted==1);
        }
         var blgos=  BloggingContext.Blogs
                .FromSql("select * from dbo.blogs")
                .Where(b=>b.BlogId>2)
                .OrderByDescending(b=>b.BlogId)
                 .Select(b=> new{ b.BlogId, b.Url})
                .ToList();
    --通过sql server profiler监听的sql,where后面加了IsDeleted==1,如下所示:
    SELECT [b].[BlogId], [b].[Url]
    FROM (
        select * from dbo.blogs
    ) AS [b]
    WHERE ([b].[IsDeleted] = 1) AND ([b].[BlogId] > 2)
    ORDER BY [b].[BlogId] DESC

  

        //可以在Linq查询语句中禁用全局查询筛选器
        BloggingContext.Blogs.IgnoreQueryFilters().ToList();

参考文献:

  原生 SQL 查询

  异步查询

  全局查询筛选器

猜你喜欢

转载自www.cnblogs.com/MrHSR/p/10444143.html