きよくらの備忘録

「三日坊主と呼ばせない!日記」改め。主にソフトウェア開発関連の話題。

DacFxを使って(C#で書いたコードを動かして)SQL Serverの差分更新スクリプトを取得する

Visual StudioのアドオンSQL Server Data Tools(以下SSDT)の機能に「スキーマ比較」ツールがあります。 これは大雑把に以下のような機能を持っています。

  • 任意の "SQL Server データベースプロジェクト(以下DBプロジェクト)" / "(オンライン状態の)データベース" / "dacpacファイル" 間でスキーマの比較を行い差異を抽出する
  • 抽出した差異を解消するための更新スクリプトを生成する

これらと同等の操作はコマンドラインツールのSqlPackage.exeでも可能であり、これらの基盤となっているDacFxを利用すれば.NETのコードで上記の操作を記述・実行することが可能です。

(多分こんなことやる/やりたい人はそうそうそういないと思うのですが自分はまた今後もやりそうな気がするので、完全に自分用のメモです)

 

差分の抽出

利用するのは DacFxに含まれる Microsoft.SqlServer.Dac.Compare.SchemaComparison クラスです。

docs.microsoft.com

このクラスは、dacpacを指す SchemaCompareDacpacEndpoint またはオンラインのデータベースを指す SchemaCompareDatabaseEndpoint をソースおよびターゲットとして比較する機能を持っています。つまり、比較対象はdacpacファイルとオンライン状態のデータベースのいずれかの組み合わせとなります。もちろんdacpac同士やデータベース同士での比較だけではなくdacpacとデータベース間での比較もできます。

(なお、SSDTのスキーマ比較機能のようにDBプロジェクトを比較対象にしたい場合は何らかの方法でDBプロジェクトからdacpacを生成した上で比較する必要がある、という事になります。その場合は 以前書いたように、Microsoft.Build.Evaluation 名前空間のあれこれを利用すればdacpacの生成処理自体も.NETのコードで記述することが可能です)

例えば以下のようなコード新旧のバージョンのdacpacを比較して差分を抽出するできました。

var newVersion = new SchemaCompareDacpacEndpoint(@"C:\some_database_v1.1.dacpac"));
var oldVersion = new SchemaCompareDacpacEndpoint(@"C:\some_database_v1.0.dacpac"));
var comparison = new SchemaComparison(newVersion, oldVersion);

var compareResult = comparison.Compare(); // 戻り値はSchemaComparisonResult型

結果は SchemaComparisonResult型 で戻されます。 例えば IEnumerable<SchemaDifference>型Differences プロパティには差分のオブジェクトの情報が列挙されますので、この中身を見ることで差分の種類やオブジェクトの名前などを取得することができます(ただし若干直感と反するようなプロパティ名かもしれない)。

foreach(var d in compareResult.Differences)
{
  // UpdateAction : 更新種別(Add or Change or Delete)
  // Name : オブジェクトの種別 (Table or Procedure or .... )
  // SourceObject.Name / TargetObject.Name : オブジェクト名
  Console.WriteLine($"更新種別:{d.UpdateAction}, オブジェクトタイプ:{d.Name}, 対象オブジェクト名:{(d.SourceObject?.Name) ?? (d.TargetObject?.Name)}");
}

 

更新用T-SQLスクリプトの取得

上記までのコードで比較はできましたが、この状態では差分を抽出しただけでありまだ更新用T-SQLスクリプトは生成されていません。これはGenerateScriptメソッドで生成できます。 GenerateScriptメソッドを実行すると戻り値としてSchemaCompareScriptGenerationResultが得られ、SchemaCompareScriptGenerationResultScriptプロパティにT-SQLスクリプトが格納されています。

雑にファイルに保存するならこんな感じでしょうか。

var generateResult = compareResult.GenerateScript("Hoge"); // 引数database name は任意の文字列。更新スクリプト中の USE [Hoge] などで使われる。
using (var sw = new System.IO.StreamWriter(@"C:\Update-Schema.sql", false, Encoding.UTF8))
{
  sw.Write(generateResult.Script);
  sw.Flush();
}

 

そのほか、Compareの第二引数側(古いバージョンのスキーマ側)がSchemaCompareDatabaseEndpointすなわちオンラインのデータベースの場合、GenerateScriptメソッドの代わりにPublishChangesToTargetメソッドを実行することで直接データベースを更新することができます。その際に実行されたT-SQLスクリプトはSchemaComparePublishResult型で返却されるPublishChangesToTargetの戻り値のScriptプロパティに格納されています。

 

まとめ

以上の通り、比較的簡単にSQL Serverのデータベースおよびdacpac間でスキーマ比較を行い差分更新用T-SQLスクリプトを生成できました。

……できましたが、オフィシャルのドキュメントが『ドキュメントコメントから生成されたシグネチャやメンバが書いてあるだけの極シンプルなAPIリファレンス』以上でも以下でもなく、利用方法などについての説明はほぼないためAPIリファレンスとインテリセンスであたりをつけつつ(基本的に同じことができるはずの)SqlPackage.exeのコマンドリファレンスを見たり おださん(@shinsukeoda) に教えてもらったサンプルコード を眺めてみたりと基本的に手さぐりだったので意外と時間がかかりました。

このほか、特定のオブジェクトを除外した更新スクリプトの生成にも無駄に時間を食ってしまったりしたのですが、またそのうち気が向いたら書いておこうと思います。

arcade1up:ディスプレイ横画面化(その1)

目指すところ

実際ギャラガ大好きだし思い入れもあるし、日本第一弾ラインナップの中ではおそらくギャラガとギャラクシアンが一番プレイ時間長いのでギャラガ/ギャラクシアンとしても楽しむ気持ちはあります。

……あるのですが、今回目指すのは購入報告のエントリ(?)でもちらっと述べた通り汎用の横画面ゲーム筐体への改造を目指そうと思ってます。

 

家庭用汎用アーケード筐体の素体としてのarcade1up

私としては現状、私が容易に安価で手にるものの中で改造の素体として最も都合が良いのがarcade1upだと考えています。

代表的なポイントはこんな感じです:

  • 比較的コンパクトでありながら小さすぎない
    • 標準で17インチLCD搭載、頑張れば19インチLCDも恐らくいける
    • 配線や機器を内蔵するための内部空間にも余裕がある
  • 適度な重さ
    • 25kgとアーケードゲーム筐体として必要十分な重さ(軽すぎると逆に使いにくさも出てくる)
    • 100kgオーバー(アストロシティ等)は移動も設置場所の選定も個人宅では色々難易度が高い
  • DIYしやすい素材
    • 構造材がMDFなので加工に必要な道具と技術が一般手な木工DIYの範囲内
    • パーツの修繕や新造も悩みが少なそう

 

横画面および2L12Bのコンパネ標準を装備している「スト2版」や「マーベルスーパーヒーローズ版」が容易に入手できればよかったのですが、現時点では国内向けには販売されておらず個人輸入するにしてもそのサイズ故に色々とハードルが高く。国内販売された中では「ランペイジ版」が横画面なのですが、気が付いたときにはどこも品切れで再入荷の見込みも薄そう……ということで一旦あきらめ、今回は安価で普通に入手できる3機種の中から一番好きなギャラガを選択することにしました。

 

LCDパネル横画面化の方針

横画面筐体にするための方法として何通りか考えました(例えば新規に17~19インチ程度のLCDパネル買って組み付ける等)。そのうえで最終的には以下の方針を取ることにしました:

  • LCDはギャラガに同梱されたものを使用
    • HDMI等汎用の入力を受け付けれるようにするLCDコントローラー(ドライバ)ユニットを購入する
  • ベゼルは横画面に合わせて新造

LCDは同梱のモノをそのまま利用し、通販で入手可能なM170ETN01.1用のHDMI対応のLCDコントローラーを購入して対応することにしました。通販で安いところで$15程度+送料、高くても国内のショップで4,000円程度で入手可能な模様。 ベゼルは9mmのMDFと2.5mmの合板で新造することにしました(12mmMDF一枚ではない理由は後述)。とりあえずホームセンターで1,500円もあれば購入できそうです。 また表面に張り付ける透明アクリルパネルは少し高くて、2,500円くらいは見積もった方が良いかもしれません。 合わせると、最大でも8000円程度の追加投資で横画面+HDMI入力対応化はできそう、という判断です。

 

横画面用ベゼルの設計

ベゼルの新造に当たって、一点だけ考えたのが「LCDを固定するための凹部」です。 f:id:kiyokura:20200922020131p:plain

この一段へこんだ部分。 f:id:kiyokura:20200923003540p:plain

オリジナルを真っ正直に再現するならば12mmMDF板を15mm程度の幅で2.5~3mm程度の高さを削ってやる感じになりますが、手持ちの工具と機材だとレベルを均一にしつつそこそこの長さを加工するのは正直ちょっと面倒だと感じました。

そこでアプローチを少し変えてみることに見ることにしました。

ベゼルをオリジナルと同様に一枚の12mmのMDFで作成するのではなく、9mmのMDFと2.5~3mm程度のMDFまたは合板*1などを張り合わせることで実現する方法です。 断面はこんな感じ。 f:id:kiyokura:20200923163050p:plain

加工は断然楽で、特に2.5mm~3mmの板の方は穴のサイズは少々大きくなっても特に問題はないはずです。唯一心配なのは強度ですが、LCD自体そこまで重くないので9mmのMDFが主の構造材であればさして影響はなさそうと思ってます。仮に問題が出ても適当な角材で裏打ちでもしてやればクリアできそう、という目算もあります。

 

ということで、ざっくり以下のような寸法で行けるかなと踏みました。 f:id:kiyokura:20200923005337p:plain

 

次回(?)

次はベゼルの新造、もしくはLCDパネルの汎用化のテストあたりをやってみようかなと思ってます。

*1:構造材というわけでもないのでMDFじゃなくてもっ安くて軽い適当な合板でも問題なさそう

arcade1up:全体的な構造についての所感やLCD パネル部の構造と(雑な)寸法など

先日購入したarcade1upギャラガ、なかなか全体を開封して組み立てる時間はないので取り急ぎディスプレイ部だけ開梱して分解・採寸したりしたのでメモ。

 

【各部品の名称は、付属の組み立て説明書に準じます(オフィシャルサイトでPDFで提供されています: https://arcade1up.jp/ のページ下部のリンクを参照)】

全体の構成

基本的には12mm程度のMDFで組まれた中空の箱です。 電気的に動作する部品は「LCD パネル(ディスプレイパネルの部分)」と「コントロールユニット(ジョイスティックなどの部分)」の部分の二か所。

CPUとかROMといった心臓部はLCD パネルにくっついています(後述)。 コントロールユニットはMDFの板に樹脂製のボックスがとりつけられていて、その中にはスイッチ類の他にスピーカーが組み込まれています。

いわば『中空の箱に薄いLCDとコントロールパネルが付いてるだけ』、といった構造のた非常にシンプルで空間に余裕がある筐体です。 排熱の対策さえできればラズパイやコンシューマゲーム機はおろかミドルタワークラスのPCでも仕込むのは難しくなさそうです。

f:id:kiyokura:20200922101038p:plain
背面から見た内部の様子(添付の組み立て説明書より抜粋、背面パネルは未取り付けの状態)

MDFなのであまり頻繁なネジの開け閉めはしないほうが良いと思いますが、木材なので加工も比較的容易ですからメンテナンスハッチを付けるなどやりようはいくらでもありそうです(そのうちやりたい)。

 

何にせよ、DIYでぼちぼち手を入れて改造していくには格好の素体だと感じています。

 

LCD パネル部の外観

表面はこんな感じ。17インチディスプレイが垂直レイアウトでベゼルに収まってる感じです。 f:id:kiyokura:20200922020404p:plain

こちらが裏側。 f:id:kiyokura:20200922020656p:plain

LCDの真ん中あたりにへばりついている生えた長方形の箱が、LCDのコントローラー(ドライバー)やらROMやらが入った、いわばこのarcade1upの本体というべきユニットです。

 

LCDの素性

LCDのラベルに「M170ETN01 1」というモデル名?のようなものが印字されているので調べてみると、どうやらOEM向けとして販売されているLCDモジュールのようです。世間では(?)「M170ETN01.1」で通っているようで、TFT方式で解像度は1280x1024…などといった情報が出てきました。 通販サイトなどでも$50から$90くらいで販売されているようで、万一つぶしてしまっても同じものは比較的容易に手に入りそうではあります。

またHDMI等の汎用的な映像入力を受け付けて駆動するLCDドライバモジュールなども通販で容易に手に入るようです(これについては後日あらためて触れる予定)。このたりも改造したいとしての素性の良さを感じます。

 

LCD パネル部の構造

LCD パネル部は大雑把に以下の3つで構成されています。

  • 透明パネル(アクリル……かもしかしたらPETかも?厚みは2mm程度)
  • LCD(と本体)
  • ベセル(MDF/12mm程度)

これらが適宜ねじ止めされています。

またベゼルは中央に穴があるだけではなくLCDの耳(?)を固定する部分が凹モールドになっています。 ざっくり図示するとこんな感じ。 f:id:kiyokura:20200922020131p:plain

断面図だとこんな感じです。 f:id:kiyokura:20200922020953p:plain

非常にシンプルで合理的な構造だと思いました。

 

採寸

LCD パネルの箱(だけ)を開梱したついでに、ざっくり採寸してみました。

f:id:kiyokura:20200922232354p:plain
arcade1up ギャラガ筐体LCDパネル部のだいたいの寸法

ただし、ノギスや指金がすぐ手元になくたまたまポケットに入ってたメジャーで雑に測っただけですので、あまり鵜呑みにはしないで欲しいなと思います*1

*1:「信じてカットしたのに合わなかった!」などと言われても責任取れません……

arcade1upのギャラガを買った

8末のことではあるのですが、arcade1upのギャラガを購入しました。

ARCADE1UP|株式会社タイトー

 

発売当初からずっと欲しかったのですが、今年の8月に入ってふと気が付いたら元々6万円ほどだったはずの定価が29,800円になっており且つ一部で期間限定という噂もあり(真偽不明)、『この価格で液晶画面付きのコンパクトでいじり易そうな(ここ重要!)アーケードゲーム筐体が買える』と考えればまあお得だな、と踏ん切りをつけました。

 

実物の3/4サイズでコンパクト……とは言え一人では少々持ちにくいサイズと形状で重量も25kgほどだったため、(こっそりと)二階に持って上がるのはしそれなりにしんどかったりしつつ。 一部の部品については開封はしたもののまだ組み立てや通電はしておらず、半倉庫状態になってる一室に置かれたままだったり。 f:id:kiyokura:20200922014527p:plain

 

今後やろうと思っているのはこのあたり:

  • ディスプレイの横置き化&汎用入力化
  • スピーカーのステレオ化
  • コントロールパネルの汎用2L12B化

まあ、ぼちぼち弄っていこうかなと思ってます。

 

(それはそれとして、カプコン版権のヤツは今からでも国内販売して欲しいです特にMarvel Super HeroesとかMarvel Super HeroesとかMarvel Super Heroesとか)

CLIツールを使わずにコード中からプロジェクトをビルドしたりdacpacをデプロイしたりする(その2)

前回の続きです。

Microsoft.SqlServer.DACFx でdacpacをデータベースにデプロイする

続いて、出来上がったdacpacファイルから Microsoft.SqlServer.DACFx を使ってデータベースにデプロイしてみる。

www.nuget.org

上記NuGetッケージを取り込んだ上で、以下のコードでごくシンプルに実現できた。

var connectionString = "<デプロイ先データベースに接続するための接続文字列>";
var databaseName = "<デプロイ先のデータベース名>";

var dac = new DacServices(connectionString);
var dacpac = DacPackage.Load(@"C:\hoge\output.dacpac");
dac.Deploy(dacpac, databaseName , true);

まとめ

以下、前回のエントリも含めてまとめる。

  • CLIツールを使用せず、NuGetで提供されているパッケージを利用することで.NETのコードだけでプロジェクトdacpacの生成とデプロイが可能
  • 今回参照したパッケージは以下
  • Microsoft.Build.Evaluation.ProjectクラスBuildメソッドによるプロジェクトのビルドについてのメモ:
    • ビルド成否はboolで返る
    • ビルドログは引数として渡したロガー経由で取得する必要がある
    • SetPropertyメソッドでプロパティをコード中から設定することが可能
    • sqlproj をビルドしてdacpacを生成する場合は Microsoft.SqlServer.DacFx の参照が必要
  • Microsoft.SqlServer.Dac.DacServicesクラスDeployメソッドによるdacpacのデプロイについてのメモ:
    • DacPackageクラスのLoadメソッド でdacpacをロードし、Deployの引数に設定してデプロイする

サンプルコード

今回検証したサンプルコードを以下に公開した github.com