FluentMigratorを使用してSSH経由でMySQLのテーブルを生成する

AWSのレンタルサーバー見つけて、シンプルなアプリ環境構築しようと思いつつ、時間があきすぎて何をやっているかわからなくなってきたので整理

  1. AWSの低額定額レンタルサーバーLightsailためしてみる
  2. 低額定額AWSサーバーLightsailにSSH接続
  3. 低額定額AWS Lightsail サーバーに静的IPアドレスを割り当てる
  4. Lightsailに構築したMySQLにMySQL Workbench から SSH接続
  5. MySQL Workbench ER図からテーブルを生成する
  6. Ubuntu(Lightsailおよびmultipass仮想) に Blazor WebAssemblyおよびASP.NET API アプリを構築してデプロイ
  7. 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に接続して確認。

テーブル生成されました。めでたし。

Migrated

Follow me!

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です