画像ファイルをDBに保存する方法として、varbinary(MAX)のカラムにバイナリデータを登録するやり方があります。本記事ではASP.NET Core + Dapper で登録する方法を紹介します。
【検証環境】Visual Studio 2019 / ASP.NET Core 3.1 / SQL Server 2019
DBに画像を保存する方法
DBに画像を保存する方法は大きく分けて2通りあります。
ファイルパスを保存
画像はDBの外に保存し、ファイルパスをデータベースに格納するやり方です。
ファイルパスを保存するだけなので、DBの容量を節約できます。
BLOB(バイナリデータ)を保存
varbinary(MAX)のカラムにバイナリデータを格納するやり方です。
レコードの容量が大きくなってしまいますが、メリットも多くあります。
それぞれの詳しいメリット・デメリットはこちらのサイトを参照してください。
サンプルコード
先にテーブルを準備します。
テーブル「Images」に カラムvarbinary(MAX)・NULL許容「Image」を作成します。
PostController と PostIndex.cshtml を作成します。
Dapperの使い方はこちらを参照して下さい。
<form method="post" enctype="multipart/form-data" asp-controller="Post" asp-action="Index">
<div class="form-file">
@*画像アップロード用*@
<input type="file" class="form-file-input" id="image" name="formFile" />
</div>
<div>
@*登録ボタン*@
<input type="submit" value="登録" name="btnname">
</div>
<div>
@*画像取得ボタン*@
<input type="submit" value="画像取得" name="btnname">
@*画像表示用*@
<img id="getimage" style="width: 100px;" src="data: image;base64,
@System.Convert.ToBase64String(ViewBag.image ?? new byte[] { })" />
</div>
<div>
@*メッセージ*@
@ViewBag.message
</div>
</form>
IFormFile で画像を受け取って、MemoryStreamにコピーして、ToArrayでbyte配列に変換すれば登録できる形式になります。
using Dapper;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Data.SqlClient;
using System.IO;
public class PostController : Controller
{
public ActionResult Index()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Index(IFormFile formFile, string btnname)
{
try
{
ViewBag.message = "";
if (btnname == "登録")
{
InsertImage(formFile, btnname);
ViewBag.message = "登録完了";
}
else if(btnname == "画像取得")
{
GetImage();
}
return View();
}
catch(Exception ex)
{
ViewBag.message = ex.Message;
return View();
}
}
private void InsertImage(IFormFile formFile, string value)
{
var connectionString = "環境に合わせてください。";
using (var connection = new SqlConnection(connectionString))
{
//接続
connection.Open();
using (var tx = connection.BeginTransaction())
{
try
{
//レコード削除
var sqlDelete = "DELETE FROM Images";
//トランザクションを使う場合、第2引数にオブジェクトを渡さないとエラーになる(空でもOK)
connection.Execute(sqlDelete, new { } ,tx);
//データ挿入
var sqlInsert = "INSERT INTO Images (Image) VALUES (@Image)";
var ms = new MemoryStream();
formFile.CopyTo(ms);
var param = new { Image = ms.ToArray() };
connection.Execute(sqlInsert, param, tx);
//コミット
tx.Commit();
}
catch (Exception)
{
//ロールバック
tx.Rollback();
throw;
}
}
}
}
private void GetImage()
{
var connectionString = "環境に合わせてください。";
using (var connection = new SqlConnection(connectionString))
{
//接続
connection.Open();
try
{
//レコード1件取得
var sql = "SELECT TOP(1) Image FROM Images";
var image = connection.QueryFirst<byte[]>(sql);
ViewBag.image = image;
}
catch (Exception)
{
throw;
}
}
}
}
アプリを起動して、URLに「/Post」を入力して遷移させます。
すると最初にこのような画面が表示されます。
画像ファイルを選択して、登録ボタンを押下すると、「登録完了」のメッセージが表示されます。
画像取得ボタンを押下すると、登録された画像が表示されることが確認できます。
DBからもバイナリデータが格納されていることが確認できます。