文章目錄
- 前言
- 一、執行查詢(返回數據)
- 1) 使用 FromSqlRaw或 FromSqlInterpolated 方法,適用于 DbSet<T>,返回實體集合。
- 2)結合 LINQ 查詢
- 3)執行任意原生SQL查詢語句(使用ADO.Net)
- 二、執行非查詢操作(增刪改)
- 1)使用 ExecuteSqlRaw() 或 ExecuteSqlInterpolated() 、ExecuteSqlInterpolatedAsync()方法,返回受影響的行數。
- 三、調用存儲過程
- 1)執行查詢存儲過程
- 2)執行非查詢存儲過程
- 四、事務處理
- 1)確保多個 SQL 操作原子性
- 五、原生 SQL 查詢的注意事項
- 總結
前言
為什么要寫原生SQL語句?
- 盡管EF Core已經非常強大,但是任然存在著無法被寫成標準EF Core調用方法的SQL語句,少數情況下任然需要寫原生SQL。
- 存在問題:可能無法跨數據庫操作。
一、執行查詢(返回數據)
1) 使用 FromSqlRaw或 FromSqlInterpolated 方法,適用于 DbSet,返回實體集合。
示例:查詢數據(建議使用FromSqlInterpolated,防止SQL注入)
var blogs = context.Blogs.FromSqlRaw("SELECT * FROM Blogs WHERE Rating > {0}", 3).ToList();// 或使用插值字符串(參數化,防注入)
var rating = 3;
var blogsSafe = context.Blogs.FromSqlInterpolated($"SELECT * FROM Blogs WHERE Rating > {rating}").ToList();
2)結合 LINQ 查詢
var filteredBlogs = context.Blogs.FromSqlInterpolated("SELECT * FROM Blogs").Where(b => b.Url.Contains("dotnet")).OrderBy(b => b.Rating).ToList();
3)執行任意原生SQL查詢語句(使用ADO.Net)
DbConnection conn=dbContext.Database.GetDbConnection();
if (conn.State != ConnectionState.Open)
{ conn.Open();
}
using (var cmd = conn.CreateCommand())
{cmd.CommandText = "select Title,Content from T_Articles where Title like '%反反復復%'";using (var reader = await cmd.ExecuteReaderAsync()){while (await reader.ReadAsync()){string title = reader.GetString(0);string content= reader.GetString(1);Console.WriteLine(title+","+content);}}}
二、執行非查詢操作(增刪改)
1)使用 ExecuteSqlRaw() 或 ExecuteSqlInterpolated() 、ExecuteSqlInterpolatedAsync()方法,返回受影響的行數。
示例:更新數據
var rowsAffected = context.Database.ExecuteSqlRaw("UPDATE Blogs SET Rating = 5 WHERE Name LIKE '%EF Core%'");// 參數化示例
var minRating = 3;
var rowsSafe = await context.Database.ExecuteSqlInterpolatedAsync($"DELETE FROM Blogs WHERE Rating < {minRating}");
三、調用存儲過程
1)執行查詢存儲過程
var blogs = context.Blogs.FromSqlRaw("EXEC GetTopRatedBlogs @p0", 5).ToList();
2)執行非查詢存儲過程
context.Database.ExecuteSqlRaw("EXEC ArchiveOldBlogs @p0", DateTime.Now.AddYears(-1));
四、事務處理
1)確保多個 SQL 操作原子性
using (var transaction = context.Database.BeginTransaction())
{try{context.Database.ExecuteSqlRaw("UPDATE Blogs SET Rating = 5 WHERE BlogId = 1");context.Database.ExecuteSqlRaw("DELETE FROM Blogs WHERE BlogId = 2");transaction.Commit();}catch{transaction.Rollback();}
}
五、原生 SQL 查詢的注意事項
- 參數化查詢:始終使用參數化輸入(如 {0} 或插值語法)避免 SQL 注入。
- 列匹配:查詢返回的列名必須與實體屬性名匹配,或通過 AS 別名映射。
- 跟蹤變更:默認跟蹤實體變更,若無需跟蹤可加 .AsNoTracking()。
- 數據庫兼容性:SQL 語法需適配具體數據庫(如 SQL Server 和 SQLite 的差異)。
- 性能:僅在必要時使用原生 SQL,優先選擇 LINQ 以保證類型安全和可維護性。
總結
一般情況下Linq操作就足夠了,盡量不要用原生SQL。
- EF Core 的原生 SQL 方法適用于特定場景,但需謹慎使用以確保安全性和可維護性。優先考慮 LINQ,復雜場景再選擇原生 SQL。
- 非查詢SQL用ExecuteSqlInterpolatedAsync()
- 針對實體的SQL查詢用FromSqlInterpolated()
- 復雜SQL查詢用ADO.NET的方式或者Dapper等。