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 INT
AS 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。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM