Error message here!

Hide Error message here!

忘记密码?

Error message here!

请输入正确邮箱

Hide Error message here!

密码丢失?请输入您的电子邮件地址。您将收到一个重设密码链接。

Error message here!

返回登录

Close

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

花阴偷移 2019-02-27 16:09:00 阅读数:204 评论数:0 点赞数:0 收藏数:0

一. 原生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 查询

异步查询

全局查询筛选器

 

版权声明
本文为[花阴偷移]所创,转载请带上原文链接,感谢
https://www.cnblogs.com/MrHSR/p/10444143.html

编程之旅,人生之路,不止于编程,还有诗和远方。
阅代码原理,看框架知识,学企业实践;
赏诗词,读日记,踏人生之路,观世界之行;

支付宝红包,每日可领