ScriptDom でクエリを改変する
ScriptDom でパースした TSqlFragment をちょっといじって、ジェネレーターで生成するクエリを改造しようという試みです。
TSqlFragment を全部コードで生成するのは結構面倒ですが、パースした後の物を変更する位なら使えるかなと思います。
今回は、複数の CREATE TABLE のスクリプトを一つのスクリプトにまとめつつ、どのテーブルにも絶対必要な共通的なカラム*1を追加してみます。
ER 図には書いてないけど DDL(CREATE TABLE) では必要なケースでは使いどころがあるかもしれませんね。
ここでは、更新者、更新日、VERSION_NO という3つのカラムを追加します。
Visitor
public class AddColumnVisitor : TSqlConcreteFragmentVisitor { /// <summary> /// CREATE TABLE を バッチ に束ねた Script /// </summary> public TSqlScript Script { get; private set; } public AddColumnVisitor() { Script = new TSqlScript(); } public override void Visit(CreateTableStatement node) { // Script に 今回の CreateTable をバッチとして追加する var batch = new TSqlBatch(); batch.Statements.Add(node); Script.Batches.Add(batch); // [更新者] nvarchar(10) var type = new SqlDataTypeReference() { SqlDataTypeOption = SqlDataTypeOption.NVarChar }; type.Parameters.Add(new IntegerLiteral() { Value = "10" }); node.Definition.ColumnDefinitions.Add(new ColumnDefinition() { ColumnIdentifier = new Identifier() { QuoteType = QuoteType.SquareBracket, Value = "更新者" }, DataType = type }); // [更新日] datetime2 node.Definition.ColumnDefinitions.Add(new ColumnDefinition() { ColumnIdentifier = new Identifier() { QuoteType = QuoteType.SquareBracket, Value = "更新日" }, DataType = new SqlDataTypeReference() { SqlDataTypeOption = SqlDataTypeOption.DateTime2 } }); // [VERSION_NO] bigint node.Definition.ColumnDefinitions.Add(new ColumnDefinition() { ColumnIdentifier = new Identifier() { QuoteType = QuoteType.SquareBracket, Value = "VERSION_NO" }, DataType = new SqlDataTypeReference() { SqlDataTypeOption = SqlDataTypeOption.BigInt } }); base.Visit(node); } }
CreateTableStatement.Definition プロパティ (Microsoft.SqlServer.TransactSql.ScriptDom) の TableDefinition.ColumnDefinitions プロパティ (Microsoft.SqlServer.TransactSql.ScriptDom) にカラムの定義を追加していきます。
CREAET TABLE のスクリプトは 3ファイル用意しました。
create table [社員マスタ] ( [Id] int not null identity(1, 1) primary key, [名前] nvarchar(20) not null, [入社日] date )create table [部門マスタ] ( [Id] int not null identity(1, 1) primary key, [名前] nvarchar(20) not null )create table [所属マスタ] ( [Id] int not null identity(1, 1) primary key, [社員Id] int not null, [部門Id] int not null )
本体のコードは大したことしてません。パース/Visitor/生成 してるだけです。
using Microsoft.SqlServer.TransactSql.ScriptDom; using System; using System.Collections.Generic; using System.IO; class Program { static void Main(string[] args) { var parser = new TSql110Parser(false); IList<ParseError> errors; TSqlFragment f; var visitor = new AddColumnVisitor(); foreach (var file in Directory.GetFiles(@".\ddl", "*.sql")) { using (var reader = File.OpenText(file)) { f = parser.Parse(reader, out errors); } // サンプルなのでエラー処理しない f.Accept(visitor); } var options = new SqlScriptGeneratorOptions() { IndentationSize = 2, KeywordCasing = KeywordCasing.Lowercase }; var generator = new Sql110ScriptGenerator(options); string output; // 出力は TextWrite でもOK! generator.GenerateScript(visitor.Script, out output); Console.WriteLine(output); Console.ReadKey(); } }
出来ましたね!ただ、残念ながらカラムの型の部分をそろえる GeneratorOption は無さそうです。。