Contents

Entity Framework Core:FromSqlRaw 與 FromSqlInterpolated 的使用與差異

Entity Framework Core (EF Core) 是一個開源的、跨平台的資料庫存取技術,它可以讓開發者用 .NET 對資料庫進行操作,而不需要寫 SQL 語句。然而,有時候我們還是需要直接執行 SQL 查詢,這時候 EF Core 提供了 FromSqlRawFromSqlInterpolated 兩種方法。

這兩種方法的主要差異在於,FromSqlRaw 需要手動參數化查詢,而 FromSqlInterpolated 則會自動參數化查詢。如果不正確使用,可能會使應用程式暴露於 SQL 注入攻擊。

以下是一些使用這兩種方法的例子和解釋:

當執行原始 SQL 查詢時,Entity Framework Core 為我們提供了兩種擴充方法:

  • FromSqlRaw
  • FromSqlInterpolated
    這兩種選項之間有些微的差異,如果不理解,可能會使應用程式暴露於 SQL 注入攻擊。

讓我們通過一些範例來理解這些差異。這邊執行一個帶有一個參數 - 專輯標題,這邊會帶去 SQL 查詢。

方法 #1:使用 FromSqlRaw

FromSqlRaw 方法需要手動參數化查詢。以下是一個例子:

1
2
3
4
5
6
[HttpGet]
[Route("albums/{title}")]
public Album Get(string title) {
    var albums = _dbContext.Album.FromSqlRaw<Album>("SELECT AlbumId, Title, ArtistId FROM Album WHERE Title = {0}", title);
    return albums.SingleOrDefault();
}

這裡是生成的 SQL 查詢。它是參數化的,並且安全。

方法 #2:使用 FromSqlRaw 和插值語法

Warning
這裡是生成的 SQL 查詢。它並未參數化,因此不安全。不建議這樣使用!

如果使用插值語法而不參數化查詢,則可能會受到 SQL 注入攻擊。以下是一個例子:

1
2
3
4
5
6
[HttpGet]
[Route("albums/{title}")]
public Album Get(string title) {
    var albums = _dbContext.Album.FromSqlRaw<Album>($"SELECT AlbumId, Title, ArtistId FROM Album WHERE Title = '{title}'");
    return albums.SingleOrDefault();
}

方法 #3:使用 FromSqlInterpolated

FromSqlInterpolated 方法會自動參數化查詢,並且支援插值語法。以下是一個例子:

1
2
3
4
5
6
[HttpGet]
[Route("albums/{title}")]
public Album Get(string title) {
    var albums = _dbContext.Album.FromSqlInterpolated<Album>($"SELECT AlbumId, Title, ArtistId FROM Album WHERE Title = {title}");
    return albums.SingleOrDefault();
}

生成的 SQL 查詢是參數化的。

在選擇使用 FromSqlRawFromSqlInterpolated 時,我們需要考慮到 SQL 注入攻擊的風險。如果我們可以確保查詢是安全的,則可以使用 FromSqlRaw 。否則,我們應該使用 FromSqlInterpolated ,因為它會自動參數化查詢,從而降低 SQL 注入攻擊的風險。

這邊看到這個 FromSqlInterpolated 方法真的很神奇。

動態欄位處理注意

FromSqlRaw 說起來還是有用的,我們做動態方法查詢 SQL,SQL 語句可能是動態的,我們可以用 FromSqlRaw 實現我們要的效果

FromSqlInterpolated 無法達成這個效果。

1
2
3
4
5
6
7
8
9
var filename = "FileName";
var value = "filexxxxx.apk";
var propertyValue = new SqlParameter("filename", value);
//"9764cb33-7ccc-4085-9136-dceab3721cd2_tw.gov.invoice_23_apps.evozi.com.apk";
var sql = "SELECT * FROM [FileLists]";
if(propertyValue != null){
	sql += " where FileName Like @filename";
}
this.FileLists.FromSqlRaw(sql, propertyValue).Dump();

在這個例子中,我們首先定義了一個 SQL 查詢,然後檢查 propertyValue 是否為 null。如果 propertyValue 不為 null,則在 SQL 查詢的末尾加上 where 條件。最後,使用 FromSqlRaw 方法執行 SQL 查詢。

然而,FromSqlInterpolated 在這種情況下無法達成我們要的效果。FromSqlInterpolated 是用於執行參數化的 SQL 查詢,但是它無法處理動態的查詢條件。在 FromSqlInterpolated 中,所有的參數都必須在查詢中明確指定,而不能像 FromSqlRaw 那樣在執行時動態地添加查詢條件。

更多關於動態 SQL 查詢的資訊,可以參考Microsoft 官方文件