1. 程式人生 > >Entity Framework Core 執行SQL語句和儲存過程

Entity Framework Core 執行SQL語句和儲存過程

無論ORM有多麼強大,總會出現一些特殊的情況,它無法滿足我們的要求。在這篇文章中,我們介紹幾種執行SQL的方法。

表結構

在具體內容開始之前,我們先簡單說明一下要使用的表結構。

    public class Category
    {

        public int CategoryID { get; set; }
        
        public string CategoryName { get; set; }
    }

Category定義了兩個欄位:CategoryIDCategoryName

    public class SampleDbContext
: DbContext { public virtual DbSet<Category> Categories { get; set; } protectedoverridevoidOnConfiguring(DbContextOptionsBuilder optionsBuilder) { var sqlConnectionStringBuilder = new SqlConnectionStringBuilder { DataSource = "10.0.1.5", InitialCatalog = "TestDataBase"
, UserID = "sa", Password = "******" }; optionsBuilder.UseSqlServer(sqlConnectionStringBuilder.ConnectionString); base.OnConfiguring(optionsBuilder); } protectedoverridevoidOnModelCreating(ModelBuilder modelBuilder
)
{ base.OnModelCreating(modelBuilder); EntityTypeBuilder<Category> entityTypeBuilder = modelBuilder.Entity<Category>(); entityTypeBuilder.ToTable("Category"); entityTypeBuilder.HasKey(e => e.CategoryID); entityTypeBuilder.Property(e => e.CategoryID).UseSqlServerIdentityColumn(); } }

我們使用SampleDbContext來訪問資料庫。

FromSql執行SQL語句

Entity Framework Core為DbSet<TEntity>提供了一個擴充套件方法FromSql,用於執行SQL語句或儲存過程,以下示例使用FromSql載入所有的資料。

        using (var dataContext = new SampleDbContext()) {
        
            var query = dataContext.Categories.FromSql("select * from Category");

            var result = query.ToList();
        }

對於帶有引數的SQL語句,我們使用C# 6 語法將SQL寫成如下:

        using (var dataContext = new SampleDbContext()) {
        
            var categoryID = 1;
            
            var query = dataContext.Categories.FromSql($"select * from Category where CategoryID={categoryID}");

            var result = query.ToList();
        }

注意:這裡不是直接使用拼接的方式處理SQL,而是轉化為引數化的SQL語句,這有助於防止SQL注入攻擊。我們可以使用SQL Server Profiler幫我們驗證:

exec sp_executesql N'select * from Category where [email protected]
',N'@p0 int',@p0=1

FromSql in Entity Framework Core

如果您不使用C# 6的語法特徵,我們必須使用 @p0、@p1 ... @pn 做為SQL語句的引數:

        using (var dataContext = new SampleDbContext()) {

            var categoryID = 1;
            var categoryName = "Product";
            
            var query = dataContext.Categories.FromSql("select * from Category where [email protected] and [email protected]"
            categoryID, categoryName);

            var result = query.ToList();

            Assert.NotNull(result);
        }

在上述SQL語句中中,將@p0對映到categoryID@ p1對映到categoryName

FromSql擴充套件方法返回的是IQueryable<TEntity>物件,要們還可以接著使用一些Linq的方法,示例如下:

       using (var dataContext = new SampleDbContext()) {

           var categoryID = 1;

           var query = dataContext.Categories.FromSql("select * from Category")
               .Where(item => item.CategoryID == categoryID)
               .OrderBy(item => item.CategoryName);

           var result = query.ToList();
       }

不過在這裡,使用的是子查詢,使用SQL Server Profiler捕獲到的SQL語句如下:

exec sp_executesql N'SELECT [item].[CategoryID], [item].[CategoryName]
FROM (
    select * from Category
) AS [item]
WHERE [item].[CategoryID] = @__categoryID_1
ORDER BY [item].[CategoryName]',N'@__categoryID_1 int',@__categoryID_1=1

提示:使用FromSql時,需要在執行的SQL語句中返回所有列,並且列名必須與實體屬性名相匹配,否則執行會出錯。

FromSql執行儲存過程

儲存過程與SQL語句寫法基本一致,使用儲存過程的示例如下:

       using (var dataContext = new SampleDbContext()) {

           var categoryID = 1;
           var query = dataContext.Categories.FromSql($"GetCategoryById {categoryID}");


           var result = query.ToList();

           Assert.NotNull(result);
       }

這些引數的順序必須與儲存過程引數的順序一致。

提示:使用FromSql執行儲存過程時,如果使用'Where'、'OrderBy'等Linq語法,這些操作不會生成SQL語句,而是在.Net中對儲存過程返回的集合進行過濾與排序。

ExecuteSqlCommand

DbContext暴露了一個Database屬性,它包括一個ExecuteSqlCommand方法。此方法返回一個整數,表示執行的SQL語句影響的行數。有效的操作是INSERTUPDATEDELETE,不能用於返回實體。

       using (var dataContext = new SampleDbContext())
       {
           var categoryID = 1;
           var categoryName = "Product";
           
           var result = dataContext.Database.ExecuteSqlCommand($"UPDATE dbo.Category SET CategoryName={categoryName} WHERE CategoryID={categoryID}");
       }