第12号(2024年04月12日)
Entity Framework CoreとJSON取込
はじめに
今回は、Entity Framework Core を使用し、JSONファイルの取込を行いました。
JSONファイルの読込、データベースへの登録方法について紹介いたします。
Entity Framework Core について
Entity Framework Core は、Microsoft社によって開発されたオブジェクトリレーショナルマッパー(O/RM)です。
オープンソースで、プラットフォームに依存しておらず、Windows、macOS、Linuxで動作するアプリケーションの開発を行えます。
SQL Server、MySQL、PostgreSQL、SQLite などさまざまなデータベースシステムをサポートしています。アプリケーション開発時にはNuGet
パッケージでそれぞれのデータベースプロバイダーをインストールする必要があります。
また、LINQ を使用し、データベースにデータを問い合わせます。LINQ はSQLデータベース、配列、List、XML文書などさまざまデータソースに
対する操作を最小限のコードで実行できます。C#の場合、「using System.Linq;」で参照することで、LINQ を使用できます。
環境について
Windows 10
Visual Studio 2022
Microsoft SQL Server Management Studio 2019
言語:C#
Entity Framework Core の入手
Entity Framework Core を使用するために、NuGetパッケージをインストールする必要があります。
Visual Studio 2022 を起動し、.NETアプリケーションのプロジェクトを作成します。
[ツール]>[NuGetパッケージマネージャー]>[パッケージ マネージャー コンソール]を開きます。
今回は、SQLServerを使用するので、以下のコマンドを実行します。
Install-Package Microsoft.EntityFrameworkCore
Install-Package Microsoft.EntityFrameworkCore.SqlServer
Install-Package Microsoft.EntityFrameworkCore.Design
Install-Package Microsoft.EntityFrameworkCore.Tools
JSONファイル取込
⓪登録するデータベースについて
テーブル項目は以下の通りとします。
①Modelの作成
クラスを使用し、Modelにデータベースの内容を定義します。
今回は、「ProductList.cs」とします。
public class ProductList
{
[Key]
public required string ID { get; set; }
public string ProductName { get; set; }
public int Stock { get; set; }
public DateTime? updatetime { get; set; }
}
②データコンテキストの作成
System.Data.Entity.DbContext から継承し、データコンテキストを作成します。
データベースとのセッションを表し、データベースとのやり取りができるようになります。
今回は、「DataContext.cs」とします。
public class DataContext : DbContext
{
public DbSet<ProductList> T_ProductList { get; set; }
public DataContext(DbContextOptions<DataContext> options) : base(options)
{
}
}
③JSONファイル読込準備
以下のコマンドを実行し、「Newtonsoft.Json」をインストールします。
「using Newtonsoft.Json.Linq;」を参照してJArrayクラスを使い、ファイル内のデータを配列に変換するためです。
Install-Package Newtonsoft.Json
④ファイルデータの読込とデータベースへの登録
今回は、以下のようなJSONファイルを取り込むものとします。
[
{
"ID": "000001",
"ProductName": "商品AAA",
"Stock": "100"
},
{
"ID": "000002",
"ProductName": "商品BBB",
"Stock": "200"
},
{
"ID": "000003",
"ProductName": "商品CCC",
"Stock": "300"
},
{
"ID": "000001",
"ProductName": "商品AAA",
"Stock": "500"
},
{
"ID": "000004",
"ProductName": "商品CCC",
"Stock": "200"
},
{
"ID": "000005",
"ProductName": "商品AAA",
"Stock": "200"
}
]
なお、ファイル内に同じデータがある場合は最上位のデータを登録、データベースに既に登録されている場合はデータを更新するものとします。
取込結果は以下のようになります。
取込部分のソース全体は以下の通りです。
var builder = new DbContextOptionsBuilder<DataContext>();
builder.UseSqlServer("接続文字列");
builder.EnableSensitiveDataLogging();
builder.EnableDetailedErrors();
using (var _context = new DataContext(builder.Options))
{
List<ProductList> lstProductList = new List<ProductList>();
string DirectoryPath = "C:\\Import";
string FileName = "importfile.json";
string FilePath = Path.Combine(DirectoryPath, FileName);
Encoding encording = Encoding.UTF8;
using (StreamReader reader = new StreamReader(FilePath, encording))
{
string allLine = reader.ReadToEnd();
JArray jArray = JArray.Parse(allLine);
int intImportCnt = 0;
bool bolAdd;
foreach (JObject jsondata in jArray)
{
ProductList? PLfile = lstProductList.FirstOrDefault(x => x.ID == jsondata["ID"].ToString());
if (PLfile == null)
{
bolAdd = false;
ProductList? PL = _context.T_ProductList.Find(jsondata["ID"].ToString());
if (PL == null)
{
PL = new ProductList()
{
ID = jsondata["ID"].ToString()
};
bolAdd = true;
}
PL.ProductName = jsondata["ProductName"].ToString();
PL.Stock = int.Parse(jsondata["Stock"].ToString());
PL.updatetime = DateTime.Now;
if (bolAdd)
{
_context.Add(PL);
}
else
{
_context.Update(PL);
}
lstProductList.Add(PL);
intImportCnt++;
}
}
}
_context.SaveChanges();
}
以下の部分では、データベースへの接続・データコンテキストのインスタンスを生成しています。
アプリケーションの種類などによりさまざまな書き方があるので、適宜変更してください。
var builder = new DbContextOptionsBuilder<DataContext>();
builder.UseSqlServer("接続文字列");
builder.EnableSensitiveDataLogging();
builder.EnableDetailedErrors();
using (var _context = new DataContext(builder.Options))
{
//取込処理
}
以下の部分では、ファイルデータの読込を行うための設定をしています。
System.IO.StreamReaderクラスを使用し、ファイルデータの読込をします。
今回は、「C:\\Import」に「importfile.json」ファイル(文字コード:UTF-8)が入っているものとします。
List<ProductList> lstProductList = new List<ProductList>(); //登録済データの格納用
string DirectoryPath = "C:\\Import"; //取込ファイルがあるフォルダ(任意)
string FileName = "importfile.json"; //取込ファイル名(任意)
string FilePath = Path.Combine(DirectoryPath, FileName); //取込ファイルパス
//ファイルの文字コードを設定
Encoding encording = Encoding.UTF8;
//ファイルのデータ読込
using (StreamReader reader = new StreamReader(FilePath, encording))
{
//データチェックや登録処理
}
以下の部分では、ファイルデータの読込とデータベースへの登録をしています。
リストやデータベースへの問い合わせにはLINQを使用しています。データコンテキストは使い終わったら、破棄する必要があります。
//ファイルのデータ読込
using (StreamReader reader = new StreamReader(FilePath, encording))
{
string allLine = reader.ReadToEnd(); //すべての入力データを読込
JArray jArray = JArray.Parse(allLine); //配列に変換
int intImportCnt = 0; //取込数
bool bolAdd; //追加か更新か
foreach (JObject jsondata in jArray)
{
//ファイル内に重複するデータがあるか
ProductList? PLfile = lstProductList.FirstOrDefault(x => x.ID == jsondata["ID"].ToString());
if (PLfile == null) //重複データなし
{
bolAdd = false; //初期化
//データベース内に重複するデータがあるか
ProductList? PL = _context.T_ProductList.Find(jsondata["ID"].ToString());
if (PL == null)
{
//新規登録
PL = new ProductList()
{
ID = jsondata["ID"].ToString()
};
bolAdd = true; //追加フラグ
}
//ID以外のデータをセット
PL.ProductName = jsondata["ProductName"].ToString();
PL.Stock = int.Parse(jsondata["Stock"].ToString());
PL.updatetime = DateTime.Now;
if (bolAdd)
{
//追加
_context.Add(PL);
}
else
{
//更新
_context.Update(PL);
}
//登録データを格納
lstProductList.Add(PL);
intImportCnt++; //取込数カウントアップ
}
}
}
//データベースを変更する
_context.SaveChanges();
追加のとき、「_context.T_ProductList.Add(PL);」のようにテーブル名を指定していません。これは直前でデータベース内の重複チェックを行う
とき「_context.T_ProductList.Find(…);」を実行しているためです。データコンテキスト内で「T_ProductList」が追跡されている状態なので、
「_context.Add(PL)」とすることができます。
また、追加の「_context.Add(PL)」をした段階では、データコンテキスト内(_context)に「PL]が追加された状態です。
「_context.SaveChanges()」を実行することで、INSERT文が発行され、データベースに反映されます。トランザクションもこのときに開始されま
す。更新や削除なども同様です。
まとめ
今回は、Entity Framwork Coreを使用し、JSONファイルの取り込みを行いました。Entity Framework CoreとLINQを使用することで、データ
の取得や追加・更新・削除などのデータベースへの問い合わせをSQL文を直接書かずに、C#のコードのみで容易にできます。コードも少ないコードで
書くことができ、見やすくなります。
しかし、非常に複雑なSQLの処理を行うときはコードが複雑になることや発行されるSQL文も複雑になり、正しいSQL文が発行されているかの確認が
わかりにくくなる可能性があるので、直接SQL文を書いた方が効率的なこともあります。
また、JSONファイルの読込については、Jarrayクラスを使用することで、データクラスを作ることなくJSON文字列を配列にすることができました。
ただし、この場合JSONファイル内のKeyがなんでも配列に変換されるので、Keyのチェックをする場合は、処理を別で入れることが必要になります。