サンプルデータベースの作成
さて、この図3のプログラムをベースに、冒頭の図1に示した帳票を出力するサンプルを組み込んでいきます。簡単に済ませるとすれば、「何かボタンをクリックすると、いつも決まった帳票が出力される」というサンプルを作ることですが、帳票出力といえば、「データベースに格納されたデータを取り出して帳票を作りたい」ということが、ほとんどではないでしょうか。
ここでは実用に寄せて、簡単なデータベースを作り、そこに格納されているデータを帳票出力するというサンプルを作ります。とはいえきちんとしたデータベースやページを作るとたいへんですし、それが本連載の目的ではないので、できるだけ簡素化します。
ここでは、マイクロソフト社の下記のページにある手順に則り、「モデルのクラスを作り、そこからデータベース、テーブル、そして、初期ページの自動生成」までを実施します。下記の工程では、サンプルとして不必要なページが作られますが、そのあたりは目をつむります。話を簡単にするため、データベースには、事前にインストールや初期設定をしておく必要がないSQLiteを使います。
【手順】サンプルデータベースの作成
[1]EF Coreツールなどのインストール
今回は、データベース操作に「Entity Framework(EF) Core」を使っていきます。そのためのツールやライブラリをインストールするため、次のコマンドを入力します。
dotnet tool install -g dotnet-aspnet-codegenerator dotnet tool install --global dotnet-ef dotnet add package Microsoft.EntityFrameworkCore.Design dotnet add package Microsoft.EntityFrameworkCore.SQLite dotnet add package Microsoft.VisualStudio.Web.CodeGeneration.Design
ツールは、ホームディレクトリの/.net/toolsフォルダにインストールされます。次のように入力して、パスを通しておきます。
export PATH="$PATH:/$HOME/.dotnet/tools"
[2]モデルを作る
ツールの準備が整ったら、まずは、テーブルの基となる「モデル」を作ります。ここでは、「注文(Order)」と「明細(Detail)」の親子関係を持つテーブルとします。exampleappフォルダの下にModelsフォルダを作り、その下にリスト2の内容で、Models.csファイルを作ります。
using System;
using System.ComponentModel.DataAnnotations;
namespace exampleapp.Models {
public class Order {
public int OrderID { get; set; }
public string Zip { get; set;}
public string Address1 {get; set;}
public string Address2 {get; set;}
public string Company {get; set;}
public string Person {get; set;}
public string Email {get; set;}
[DataType(DataType.Date)]
public DateTime OrderDate { get; set; }
public ICollection<Detail> Details {get; set;}
}
public class Detail {
public int ID { get; set; }
public int OrderID {get; set;}
public string ProductName { get; set;}
public decimal UnitPrice {get; set;}
public int Quantity {get; set;}
}
}
EF Coreで扱う場合、プロパティに命名規則があります。ここでは、次の命名規則に従っています。
- 主キー:「ID」や「クラス名+ID」を付けると、それは主キーとして扱われます(「OrderID列」および「ID列」)。
- リレーション:親子関係は、「ICollection<クラス名>」で構成します(OrderとDetailの関係)。子が親を参照する外部キーは、「クラス名+ID」で命名します(DetailクラスのOrderIDプロパティ)。
[3]ページを自動生成する
このモデル定義から、データベースへの接続定義や一覧や編集、削除のページなど、必要なコード一式を自動で生成します。
まずは、Orderテーブルについて、次のようにして作成します(ここでは「Pages/Orders」のように、-outDirオプションを「Orders」としている点に注意してください。Ordersである必要はないのですが、「Order」のようにモデルのクラス名と同じにすると「ページ名」と「モデルのクラス名」が同名になり、ビルド時にエラーが発生します)。
dotnet-aspnet-codegenerator razorpage -m Order -dc MyAppContext -udl -outDir Pages/Orders --referenceScriptLibraries -sqlite
同様にして、Detailテーブルについて作成します。
$HOME/.dotnet/tools/dotnet-aspnet-codegenerator razorpage -m Detail -dc MyAppContext
[4]データベースやテーブルを作る
これでPagesフォルダ以下に、「Orders」と「Details」のフォルダができ「一覧(Index)」「新規作成(Create)」「編集(Edit)」「削除(Delete)」の4つのページが作成されます。しかしデータベースもテーブルもまだないので、実行して開いてもエラーが発生するだけです。そこでデータベースとテーブルを作成していきましょう。
EF Coreには、このモデルから、自動でデータベースやテーブル自体を作成するマイグレーション機能があります。まず、次のように入力します。
dotnet ef migrations add InitialCreate
するとMigrationディレクトリ以下に、データベースやテーブルを作成するためのプログラムが自動生成されます。これをデータベースに反映するため、下記のコマンドを入力します。このコマンド入力によって、実際にデータベースとテーブルが作成されます。
dotnet ef database update
[5]動作確認する
この段階で動作確認しておきます。ビルドして起動します。
dotnet publish -c Release -o published
dotnet published/exampleapp.dll
ブラウザで、「http://localhost:5000/Orders/」を開きます。すると、Orderテーブルの一覧が表示されます(図5)。ここで[Create New]のリンクをクリックすると、新しい注文を作成できますが、何もしないでおいてください(以下の手順では、「何もレコードが存在しないとき」に限って、初期データを作成するプログラムを作るため、何かデータを入れると次の手順で失敗します)。
初期データの投入
まだテーブルの中身が空なので、サンプルのデータを投入します。いくつかのやり方がありますが、ここでは「何もレコードが存在しないとき」に限って、初期データを作成するプログラムを作ります。
あまり手間をかけたくないので、Program.csをリスト3のように書き換えます。書き換えた箇所には「★印」を付けました。
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
// ★追加★
using exampleapp.Models;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddDbContext<MyAppContext>(options =>
options.UseSqlite(builder.Configuration.GetConnectionString("MyAppContext")));
var app = builder.Build();
// ★初期化データ投入 ここから★
using (var scope = app.Services.CreateScope()){
var services = scope.ServiceProvider;
using (var context = services.GetRequiredService<MyAppContext>()) {
if (!await context.Order.AnyAsync()) {
var order = new Order {
Zip = "123-4567",
Address1 = "東京都新宿区",
Address2 = "1-2-3 ●●ビル",
Company = "株式会社●●",
Person = "山田一郎",
Email = "yamada@example.co.jp",
OrderDate = DateTime.Today,
Details = new List<Detail> {
new Detail{ ProductName = "製品A", UnitPrice = 100, Quantity = 5},
new Detail{ ProductName = "製品B", UnitPrice = 300, Quantity = 3},
new Detail{ ProductName = "製品C", UnitPrice = 400, Quantity = 1},
}
};
context.Order.Add(order);
await context.SaveChangesAsync();
}
}
}
// ★追加ここまで★
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapRazorPages();
app.Run();
このように修正してビルドして実行し、先ほどと同様に「http://localhost:5000/Orders/」を確認すると、初期データが入っていることがわかります(図6)。図6には表示されていませんが、実際には明細も入っています。

