MLBお兄さんこと松村です。
この記事はオルターブース Advent Calendar 2021の5日目の記事です。
adventar.org
前回の記事に引き続き、今回も Azure Functions の Azure SQL バインディングを試した内容になります。前回の記事はこちらから。
aadojo.alterbooth.com
前回は入力バインディングを試したので、今回は出力バインディングを試してみます。
Azure SQL の出力バインディングは、データの保存を行うことができる機能になっています。
docs.microsoft.com
Azure SQL の出力バインディングは他の出力バインディングと同様に、引数にオブジェクトをセットすることで関数終了時にデータの保存が行われます。
単一オブジェクトの引数なら 1件のデータの保存となります。
ICollector<T>
または IAsyncCollector<T>
の引数なら複数件のデータの保存となります。
バインド定義
入力バインディングと同様に Microsoft.Azure.WebJobs.SqlAttribute
の属性付きの引数を用意します。
1件のレコードを保存する場合
public IActionResult Run( [HttpTrigger(AuthorizationLevel.Function, "get", Route = null)] HttpRequest req, [Sql("dbo.ToDo", ConnectionStringSetting = "SqlConnectionString")] out ToDoItem newItem)
複数件のレコードを保存する場合(同期)
public IActionResult Run( [HttpTrigger(AuthorizationLevel.Function, "get", Route = null)] HttpRequest req, [Sql("dbo.ToDo", ConnectionStringSetting = "SqlConnectionString")] ICollector<ToDoItem> newItems)
複数件のレコードを保存する場合(非同期)
public async Task<IActionResult> Run( [HttpTrigger(AuthorizationLevel.Function, "get", Route = null)] HttpRequest req, [Sql("dbo.ToDo", ConnectionStringSetting = "SqlConnectionString")] IAsyncCollector<ToDoItem> newItems)
なお、既知の問題がいくつかあるようです。 Azure SQL バインディング自体がプレビューということもあり、用法用量を守って使いましょう。
https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-bindings-azure-sql#known-issues
書き方は単純なのでサンプルコードを真似て書けばいいですが、1つ気になることがあります。
レコードの更新はできるのか?
2つのパターンを試して確認してみます。
- 既存の主キーをもつレコードを出力バインドで保存する
- 入力バインドで取得したレコードを出力バインドで保存する
1. 既存の主キーをもつレコードを出力バインドで保存する
まず既存のレコードを確認します。(主キーは Id
列です)
同じ主キーの値でレコードを出力バインドで保存します。
[FunctionName("WriteOneRecord")] public static IActionResult Run( [HttpTrigger(AuthorizationLevel.Function, "get", Route = "addtodo")] HttpRequest req, [Sql("dbo.ToDo", ConnectionStringSetting = "SqlConnectionString")] out ToDoItem newItem) { newItem = new ToDoItem { Id = 1, Priority = 200, Description = "new-description1" }; return new CreatedResult($"/api/addtodo", newItem); }
この関数を実行すると、主キーが該当する既存レコードが更新されました。つまり SQL の UPDATE
クエリが実行されたことになります。
2. 入力バインドで取得したレコードを出力バインドで保存する
前回の記事で紹介した入力バインドで取得したレコードを変更し、出力バインドで保存してみます。
[FunctionName("UpdateOneRecord")] public static IActionResult Run( [HttpTrigger(AuthorizationLevel.Function, "get", Route = "updatetodo/{id}")] HttpRequest req, [Sql("select * from dbo.ToDo where Id = @Id", CommandType = System.Data.CommandType.Text, Parameters = "@Id={id}", ConnectionStringSetting = "SqlConnectionString")] IEnumerable<ToDoItem> items, [Sql("dbo.ToDo", ConnectionStringSetting = "SqlConnectionString")] out ToDoItem newItem) { var item = items.First(); newItem = item; newItem.Priority = 300; newItem.Description = "update-description1"; return new NoContentResult(); }
この関数を実行すると SELECT
クエリで取得したレコードを更新できることが分かります。
- 出力バインドで保存するレコードが Azure SQL に存在しない場合は
INSERT
が実行される - 出力バインドで保存するレコードが Azure SQL に存在する場合は
UPDATE
が実行される
つまり UPSERT の挙動になるようです。
2回に分けて Azure Functions の Azure SQL バインディングを試してみました。プレビューとはいえ基本的なことはできることが分かりました。
Azure Functions で O/R マッパー等を使わなければならない、という場面が少しでも減るといいなと思います。GA に期待!