EntityFramework Core Raw SQL

前言

本节我们来讲讲EF Core中的原始查询,目前在项目中对于简单的查询直接通过EF就可以解决,但是涉及到多表查询时为了一步到位就采用了原始查询的方式进行。下面我们一起来看看。

EntityFramework Core Raw SQL

基础查询(执行SQL和存储过程)

啥也不说了,拿起键盘就是干,如下:

    public class HomeController : Controller
    {
        private IBlogRepository _blogRepository;
        public HomeController(IBlogRepository blogRepository)
        {
            _blogRepository = blogRepository;
        }
        public IActionResult Index()
        {
            var list = _blogRepository.GetList();
            return Ok();
        }
    }
    public class BlogRepository : EntityBaseRepository<Blog>,
        IBlogRepository
    {
        private EFCoreContext _efCoreContext;
        public BlogRepository(EFCoreContext efCoreContext) : base(efCoreContext)
        {
            _efCoreContext = efCoreContext;
        }

        public IEnumerable<Blog> GetList()
        {
            var iQueryTable = _efCoreContext.Set<Blog>().
                FromSql("select * from Blog");
            return iQueryTable.ToList();
        }
    }

下面我们来看看存储过程。

CREATE PROCEDURE dbo.GetBlogList
AS
BEGIN
    SELECT * FROM dbo.Blog
END
GO
        public IEnumerable<Blog> GetList()
        {
            var iQueryTable = _efCoreContext.Set<Blog>().
                FromSql("EXECUTE  dbo.GetBlogList");
            return iQueryTable.ToList();
        }

参数查询 

利用参数化存储过程查询。

ALTER PROCEDURE [dbo].[GetBlogList]
@id INTAS
BEGIN
    SELECT * FROM dbo.Blog WHERE Id = @id
END

结果利用FromSql就变成了如下:

        public IEnumerable<Blog> GetList()
        {
            var Id = new SqlParameter("Id", "1");
            var iQueryTable = _efCoreContext.Set<Blog>().
                FromSql("EXEC dbo.GetBlogList {0}", 1);
            return iQueryTable.ToList();
        }

上述是利用string.format的形式来传参,我们也可以利用SqlParameter来传参,如下:

        public IEnumerable<Blog> GetList()
        {
            var Id = new SqlParameter("Id", "1");
            var iQueryTable = _efCoreContext.Set<Blog>().
                FromSql("EXEC dbo.GetBlogList @id", Id);
            return iQueryTable.ToList();
        }

我们通过开启调试,可以清晰看到执行的存储过程。

通过如上我们知道参数化查询有两种形式,下面我们再来看看linq查询。

linq查询

上述我们演示一直直接使用FromSql,其实在此之后我们可以继续通过linq来进行查询,如下:

        public IEnumerable<Blog> GetList()
        {
            var Id = new SqlParameter("Id", "2");
            var iQueryTable = _efCoreContext.Set<Blog>().
                FromSql("EXEC dbo.GetBlogList @id", Id).Where(d => d.Name == "efcore2");
            return iQueryTable.ToList();
        }

之前我们映射了Blog和Post之间的关系,这里我们只能查询出Blog表的数据,通过对上述linq的讲解,我们完全可以通过inlcude来显式加载Post表数据,如下:

        public IEnumerable<Blog> GetList()
        {
            var Id = new SqlParameter("Id", "2");
            var iQueryTable = _efCoreContext.Set<Blog>().
                FromSql("EXEC dbo.GetBlogList @id", Id).Include(d => d.Posts);
            return iQueryTable.ToList();
        }

好吧,明确告诉我们对于存储过程是不支持Inlude操作的,所以要想Include我们只能进行简单的查询,如下:

        public IEnumerable<Blog> GetList()
        {
            var iQueryTable = _efCoreContext.Set<Blog>().
                FromSql("select * from blog").Include(d => d.Posts);
            return iQueryTable.ToList();
        }

查找官网资料时发现居然对表值函数(TVF)是可以Include的,创建内嵌表值函数如下:

USE [EFCoreDb]
GO

IF OBJECT_ID('dbo.GetBlog') IS NOT NULL
    DROP FUNCTION dbo.GetBlog;
GO

CREATE FUNCTION dbo.GetBlog
    (@Name VARCHAR(max)) RETURNS TABLE WITH SCHEMABINDING
AS
RETURN
 SELECT Id, Name, Url FROM dbo.Blog WHERE Name = @Name
GO

调用如下:

        public IEnumerable<Blog> GetList()
        {
            var name = "efcore2";
            var iQueryTable = _efCoreContext.Set<Blog>().
                FromSql("select * from [dbo].[GetBlog] {0}", name).Include(d => d.Posts);
            return iQueryTable.ToList();
        }

结果出乎意料的出现语法错误:

通过SQL Server Profiler查看发送的SQL语句如下:

这能不错么,官网给的示例也是和上述一样,如下:

只是按照和他一样的搬过来了,未曾想太多,还是粗心大意了,想了好一会,按照我们正常调用表值函数即可,我们需要用括号括起来才行,如下:

        public IEnumerable<Blog> GetList()
        {
            var name = "efcore2";
            var iQueryTable = _efCoreContext.Set<Blog>().
                FromSql("select * from [dbo].[GetBlog] ({0})", name).Include(d => d.Posts);
            return iQueryTable.ToList();
        }

上述将[dbo.GetBlog]和({0})隔开和挨着都可以。这个时候才不会出现语法错误。执行的SQL如下才是正确的。

好了,到了这里关于EF Core中原始查询我们就告一段落了,其中还有一个知识点未谈及到,在EF Core我们可以直接通过底层的ADO.NET来进行查询,我们来看下:

底层ADO.NET查询

        public IEnumerable<Blog> GetList()
        {
            var list = new List<Blog>();
            using (var connection = _efCoreContext.Database.GetDbConnection())
            {
                connection.Open();

                using (var command = connection.CreateCommand())
                {
                    command.CommandText = "SELECT * FROM dbo.Blog";

                    using (SqlDataReader reader = command.ExecuteReader() as SqlDataReader)
                    {
                        while (reader.Read())
                        {
                            var blog = new Blog();
                            blog.Id = Convert.ToInt32(reader["Id"]);
                            blog.Name = reader["Name"].ToString();
                            blog.Url = reader["Url"].ToString();
                            list.Add(blog);
                        }
                    }
                }
            }
            return list;
        }

总结

我们本节讲述了EF Core中的原始查询,相比较之前EF版本的原始查询使用更加灵活了一点,但是缺陷还是展露无遗,依然只能查出所有的列且必须匹配,同时呢,若我们想执行事务,目前还不支持底层的TranscationScope仅仅支持BeginTranscation。

时间: 2024-09-20 17:52:59

EntityFramework Core Raw SQL的相关文章

EntityFramework Core Raw Query再叙注意事项后续

前言 话说通过EntityFramwork Core进行原始查询又出问题,且听我娓娓道来. EntityFramework Core Raw Query后续 当我们进行复杂查询时我们会通过原始查询来进行,我们定义如下ViewModel public class BlogViewModel { public int Id { get; set; } public string Name { get; set; } public string Url { get; set; } public str

EntityFramework Core Raw Query再叙注意事项

前言 最近一直比较忙没有太多时间去更新博客,接下来会一直持续发表相关内容博客,上一篇我们讲到了EF Core中的原始查询,这节我们再来叙述一下原始查询,本文是基于在项目当中用到时发现的问题. 话题 我们通过EF Core原始查询主要是用于一些需要连接多个表进行复杂查询,下面我们来回顾下.我们定义一个ViewModel. public class BlogViewModel { public string Name { get; set; } public string Url { get; se

EntityFramework 7 更名为EntityFramework Core(预发布状态)

前言 最近很少去学习和探索新的东西,尤其是之前一直比较关注的EF领域,本身不太懒,但是苦于环境比较影响自身的心情,所以迟迟没有下笔,但是不去学习感觉在精神层面缺少点什么,同时也有园友说EF又更新了,要我再写一篇,最终经过思想斗争后,还是花了一点时间去继续探索.本篇比较理论的去分享最近EF进展,后面有时间会继续关注EF团队在EF上的动向,并给出相对应的实例. EF Core 1.0.0 (1)EntityFramework是微软在.NET中推荐使用的数据访问技术,而EntityFramework

EntityFramework Core 1.1有哪些新特性呢?我们需要知道

前言 在项目中用到EntityFramework Core都是现学现用,及时发现问题及时测试,私下利用休闲时间也会去学习其他未曾遇到过或者用过的特性,本节我们来讲讲在EntityFramework Core 1.1中出现了哪些新特性供我们使用. EntityFramework Core 1.1新特性探讨 DbSet.Find 在EF 6.x中也有此方法的实现,在EF Core 1.1中也同样对此方法进行了实现,为什么要拿出来讲呢,当然也有其道理,我们一起来看看.在仓储中我们实现Find这个方法,

EntityFramework Core并发深挖详解,一纸长文,你准备好看完了吗?

前言 之前有关EF并发探讨过几次,但是呢,博主感觉还是有问题,为什么会觉得有问题,其实就是理解不够透彻罢了,于是在项目中都是用的存储过程或者SQL语句来实现,利用放假时间好好补补EF Core并发的问题,本文比较长,请耐心点看. EntityFramework Core并发初级版初探 关于并发无非就两种:乐观并发和悲观并发,悲观并发简言之则是当客户端对数据库中同一值进行修改时会造成阻塞,而乐观并发则任何客户端都可以对可以对数据进行查询或者读取,在EF Core中不支持悲观并发,结果则产生并发冲突

EntityFramework Core并发导致显式插入主键问题

前言 之前讨论过EntityFramework Core中并发问题,按照官网所给并发冲突解决方案以为没有什么问题,但是在做单元测试时发现too young,too simple,下面我们一起来看看. .NET Core 1.1单元测试问题 我们循序渐进,首先从单元测试开始说起,可能其中就有你在.NET Core上进行单元测试会遇到的问题,别着急,不妨一看.我们需要创建.NET Core类库,,如下: 接下来对project.json进行如下修改. { "version": "

EntityFramework Core不得不注意的性能优化意外收获,你会用错?

前言 这两天在着实研究EF Core项目当中对于一些查询也没实际去检测,于是想着利用放假时间去实际测试下,结果本文就出来了,too young,too simple,后续博主会从底层翻译表达式树弄起,来从源头了解EF Core,通过本文你会明白不是EF Core团队没做性能优化,而是你根本就没用过而且正在倒退. EntityFramework Core性能优化初探 简单粗暴直接上代码,给出上下文以及需要用到的测试类,如下: public class EFCoreContext : DbConte

神马玩意,EntityFramework Core 1.1又更新了?走,赶紧去围观

前言 哦,不搞SQL了么,当然会继续,周末会继续更新,估计写完还得几十篇,但是我会坚持把SQL更新完毕,绝不会烂尾,后续很长一段时间没更新的话,不要想我,那说明我是学习新的技能去了,那就是学习英语,本来没有打算再探究目前.NET中跨平台的东西,毕竟才出来没多久,还是有很多坑,希望有人踩过再来学习会好很多,可惜项目中都是用的最新的东西,我不得不去探索,于是有关EntityFramework Core的坑就这么出来了,来,我们一起看看. EntityFramework Core 1.1迁移 我们首先

EntityFramework Core饥饿加载忽略导航属性问题

前言 .NET Core项目利用EntityFramework Core作为数据访问层一直在进行中,一直没有过多的去关注背后生成的SQL语句,然后老大捞出日志文件一看,恩,有问题了,所以本文产生了,也是有点疑惑,若有知情者,还望告知. EntityFramework Core忽略导航属性  在前面我们已经探讨过利用Serilog日志框架来输出日志,所以对于本节查询日志的输出依然借助Seilog.我们在Startup.cs类中Starup方法中是创建日志实例. Log.Logger = new L