FluentMigratorを使用してSSH経由でMySQLのテーブルを生成する
AWSのレンタルサーバー見つけて、シンプルなアプリ環境構築しようと思いつつ、時間があきすぎて何をやっているかわからなくなってきたので整理
- AWSの低額定額レンタルサーバーLightsailためしてみる
- 低額定額AWSサーバーLightsailにSSH接続
- 低額定額AWS Lightsail サーバーに静的IPアドレスを割り当てる
- Lightsailに構築したMySQLにMySQL Workbench から SSH接続
- MySQL Workbench ER図からテーブルを生成する
- Ubuntu(Lightsailおよびmultipass仮想) に Blazor WebAssemblyおよびASP.NET API アプリを構築してデプロイ
- Ubuntu(Lightsailおよびmultipass仮想環境)のMySQLにローカルからSSH経由で接続
とりあえず、AWSのLightsail環境と、自宅にmultipassで近しい開発環境を作って同じように接続できるようにして、.NET+MySQLの環境を作っていたっぽい。
ワークベンチでER図書いて、DDLに落とし込む確認したのだけれど、個人で遊ぶ分には、モデルベースで開発できた方が楽だよなということで、マイグレーションツール探す。
FluentMigrator が良さそう
EntityFrameworkは死ぬほど遅いのと、基本オーバースペックなので、マイグレーション機能は便利だった気がするけど使いたくない。
Dapper+自作Daoでいい。
FluentMigrator
https://github.com/fluentmigrator/fluentmigrator
https://www.nuget.org/packages/FluentMigrator
Document
https://fluentmigrator.github.io/
で、モデルからマイグレーションできるとよいのだが、
EasyMigrator.FluentMigrator
https://www.nuget.org/packages/EasyMigrator.FluentMigrator
.NET Frameworkにしか対応していない。。。.NET で動くか試すのも面倒だ。。
POCOのモデルはどうやって作ればいいのかしら、、、と思いつつ、
まずチュートリアル試す。
ただ試すのではなく、前回疎通した、SSH経由でMySQLに接続してマイグレーションする感じで。
1.SSHサーバーに接続するメソッドと、SSH接続経由でDBに接続するメソッドを持つクラス
using Renci.SshNet;
namespace SetlistShare.Dao;
/// <summary>
///
/// </summary>
public class ConnectionHelper
{
///<summary>SSH接続</summary>
/// <param name="host">ホスト名</param>
/// <param name="username">ユーザー名</param>
/// <param name="password">パスワード</param>
/// <param name="keyFile">秘密鍵ファイル</param>
/// <param name="passPhrase">秘密鍵のパスフレーズ</param>
/// <param name="port">ポート番号</param>
public static (SshClient sshClient, int Port) ConnectSsh(
string host,
string username,
string? password = null,
string? keyFile = null,
string? passPhrase = null,
int port = 22)
{
if (string.IsNullOrEmpty(password) && string.IsNullOrEmpty(keyFile))
{
throw new ArgumentException("Either password or keyFile must be specified.");
}
var authMethods = new List<AuthenticationMethod>();
if (!string.IsNullOrEmpty(keyFile))
{
var key = new PrivateKeyFile(keyFile, passPhrase);
authMethods.Add(new PrivateKeyAuthenticationMethod(username, key));
}
if (!string.IsNullOrEmpty(password))
{
authMethods.Add(new PasswordAuthenticationMethod(username, password));
}
var connectionInfo = new ConnectionInfo(host, port, username, authMethods.ToArray());
var sshClient = new SshClient(connectionInfo);
sshClient.Connect();
return (sshClient, port);
}
///<summary>SSH接続</summary>
/// <param name="host">ホスト名</param>
/// <param name="username">ユーザー名</param>
/// <param name="password">パスワード</param>
/// <param name="keyFile">秘密鍵ファイル</param>
/// <param name="passPhrase">秘密鍵のパスフレーズ</param>
/// <param name="port">ポート番号</param>
public static (SshClient sshClient, int Port) ConnectDatabaseViaSsh(
string host,
string username,
string? password = null,
string? keyFile = null,
string? passPhrase = null,
int port = 22,
string? dbHost = "localhost",
int dbPort = 3306)
{
var (sshClient, sshPort) = ConnectSsh(host, username, password, keyFile, passPhrase, port);
var forwardPort = new ForwardedPortLocal("127.0.0.1", dbHost, (uint)dbPort);
sshClient.AddForwardedPort(forwardPort);
forwardPort.Start();
return (sshClient, (int) forwardPort.BoundPort);
}
}
2.テーブルのマイグレーション用クラス
using FluentMigrator;
namespace Migrator;
[Migration(1)]
public class AddPersonTable : Migration
{
public override void Up()
{
Create.Table("Person")
.WithColumn("Id").AsInt64().PrimaryKey().Identity()
.WithColumn("Name").AsString(255).NotNullable()
.WithColumn("Age").AsInt32().NotNullable()
.WithColumn("CreatedAt").AsDateTime().NotNullable()
.WithColumn("CreatedBy").AsString().NotNullable()
.WithColumn("UpdatedAt").AsDateTime().NotNullable()
.WithColumn("UpdatedBy").AsString().NotNullable();
}
public override void Down()
{
Delete.Table("Person");
}
}
3.マイグレーション実行
using FluentMigrator.Runner;
using Microsoft.Extensions.DependencyInjection;
using MySql.Data.MySqlClient;
using SetlistShare.Dao;
namespace SetlistShare.Migrate;
public class Program
{
public static void Main(string[] args)
{
Console.WriteLine("Migration started");
var (sshclient, port) = ConnectionHelper.ConnectDatabaseViaSsh (
"lightsail.local",
"piroto",
"north123");
using (sshclient)
using(var serviceProvider = CreateServices(port))
using(var scope = serviceProvider.CreateScope())
{
UpdateDatabase(scope.ServiceProvider);
}
}
///<summary>サービスを登録する</summary>
///<param name="sshPort">SSH接続でフォワーディングするSSHポート</param>
private static ServiceProvider CreateServices(int sshPort)
{
// SSH接続のために、ポートフォワーディングを行う
// 本番環境では、ポートフォワーディングを行う必要はないが、ローカルから接続して実施するため必要
var builder = new MySqlConnectionStringBuilder
{
Server = "127.0.0.1",
Port = (uint)sshPort,
UserID = "setlistshare",
Password = "Kings@Straw123",
Database = "setlistshare"
};
return new ServiceCollection()
.AddFluentMigratorCore()
.ConfigureRunner(rb => rb
.AddMySql5()
.WithGlobalConnectionString($"{builder.ConnectionString};")
.ScanIn(typeof(Program).Assembly).For.Migrations())
.AddLogging(lb => lb.AddFluentMigratorConsole())
.BuildServiceProvider(false);
}
///<summary>データベースを更新する</summary>
/// <param name="serviceProvider">サービスプロバイダ</param>
private static void UpdateDatabase(IServiceProvider serviceProvider)
{
var runner = serviceProvider.GetRequiredService<IMigrationRunner>();
runner.MigrateUp();
}
}
}
bengalure:Migrate piroto$ dotnet run Migration started ------------------------------------------------------------------------------- 1: AddPersonTable migrating ------------------------------------------------------------------------------- Beginning Transaction CreateTable Person Committing Transaction 1: AddPersonTable migrated
A5SQL Mk2でDBに接続して確認。
テーブル生成されました。めでたし。


