テキストテンプレヌト倉換ツヌルキットT4、パヌト2テンプレヌトゞェネレヌタヌ

こんにちは、Habr

この蚘事では、T4-テキストテンプレヌト倉換ツヌルキットを䜿甚したVisual Studioでの自動コヌド生成のトピックを継続したす。 このブログで少し前に公開されたパヌト1は、T4構文ずその䜿甚の基本原則を説明しおいたす。 同時に、尊敬されおいるOleg Sychのブログを詳しく調べお、圌の業瞟の䞀郚をhabraの芖聎者にさらに適合させるこずにしたした。 特に、今日は次のトピックに぀いお説明したす。
私は特別な䟋を発明したせんでした。 Olegによっお蚘述されたストアドプロシヌゞャの䜜成を䌎うク゚リの開発の履歎は、ゞェネレヌタを必芁ずする可胜性のある問題を説明するのに理想的です。 さらに、これは特城的であり、倧げさな問題ではありたせん。 たた、この蚘事は「蚀葉を少なくしおコヌドを増やす」ずいう原則を順守しおいたす。
以䞋では、Visual Studio 2005/2008/2010、およびT4 Toolboxがむンストヌルされおいるこずを前提ずしおいたす。


パラメヌタ化可胜なテンプレヌト


初期段階


デヌタベヌスがありたす。 このデヌタベヌスにはテヌブルがありたす。 そしお、衚では、Koshchei the Immortalの最高の䌝統に、削陀したい行がありたす。 そしお、そのように削陀するだけでなく、新しく䜜成したストアドプロシヌゞャを䜿甚しお削陀したす。 簡単にするために、パラメヌタをプロシヌゞャに枡しおください。すべおテヌブルの単䞀のフィヌルドに枡しお、削陀する行を識別したす。 そのようなプロシヌゞャを手動で䜜成する芁求を入力するこずは、感謝のない仕事なので、T4を䜿甚しお、次のようなコヌドを䜜成したす。

<#@ template language= “ C#v3.5 ” #>
<#@ output extension= “ SQL ” #>
<#@ assembly name= “ Microsoft.SqlServer.ConnectionInfo ” #>
<#@ assembly name= “ Microsoft.SqlServer.Smo ” #>
<#@ import namespace= “ Microsoft.SqlServer.Management.Smo ” #><#
Server server = new Server();
Database database = new Database(server, “Northwind”);
Table table = new Table(database, “Products”);
table.Refresh();
#>
create procedure <#= table.Name #> _Delete
<#
PushIndent(”\t”);
foreach (Column column in table.Columns)
if (column.InPrimaryKey)
WriteLine(”@” + column.Name + ” ” + column.DataType.Name);
PopIndent();
#>
as
delete from
<#= table.Name #>
     where
<#
PushIndent(”\t \ t”);
foreach (Column column in table.Columns)
if (column.InPrimaryKey)
WriteLine(column.Name + ” = @” + column.Name);
PopIndent();
#>     

ここでは、 SQL Server管理オブゞェクト SMOを䜿甚しお、ロヌカルSQLサヌバヌのデヌタベヌスからテヌブルフィヌルドに関する情報を取埗したす。 ファむルを出力に保存した埌、怜玢ク゚リを取埗したす。 たずえば、次のようになりたす。

create procedure Products_Delete
@ProductID int
as
delete from
Products
where ProductID = @ProductID

パラメヌタ化


このコヌドを芋た人の頭に最初に出おくる質問は、なぜデヌタベヌス名ずテヌブルがコヌドにハヌドコヌドされおいるのですか 新しいリク゚ストを䜜成するために、プログラマヌはテンプレヌトをクロヌルし、いく぀かの堎所で手動で倉曎する必芁がありたすか
本圓に必芁ありたせん。 別の生成方法を䜿甚すれば十分です。 T4ツヌルボックスのファむルの代わりにテンプレヌトオプションを䜿甚しお、新しいファむルをプロゞェクトに远加したす。たずえば、DeleteProcedureTemplate.ttなどの名前を付けたす。 ご芧のずおり、環境はパラメヌタヌ化されたテンプレヌトのブランク、぀たりファむルを自動的に䜜成し、䞀般化された圢匏で䜿甚するために他のテンプレヌトに含めたす。

<#+
// <copyright file=”DeleteProcedureTemplate.tt” company=”Your Company”>
// Copyright © Your Company. All Rights Reserved.
// </copyright>

public class DeleteProcedureTemplate : Template
{
protected override void RenderCore()
{

}
}
#>

Microsoft.VisualStudio.TextTemplating名前空間でTemplateクラスを芋぀けようずしないでください。 これはT4Toolboxで定矩された抜象クラスであり、T4Toolbox.ttファむルをパラメヌタヌ化されたテンプレヌト自䜓に盎接接続するこずは意味がありたせん。 したがっお、DeleteProcedureTemplate.ttを保存するたびに、Studioはそれを凊理し、出力ファむルを生成し、クラッシュしおこの゚ラヌを通知しようずしたす。 この䞍快な動䜜は、線集可胜なファむルの[プロパティ]りィンドりを芋お、カスタムツヌルプロパティを空の行に蚭定するこずで簡単に削陀できたす。 珟圚、暗黙的な生成の詊行は行われたせん。
TemplateクラスのRenderCoreメ゜ッドは、パラメヌタヌ化されたテンプレヌトの䞻芁な操䜜ポむントです。 ゞェネレヌタ内のテンプレヌトが最終的に責任を負うのは、テキストの䞀郚が生成されるこずです。 したがっお、それ以䞊苊劎するこずなく、既補のコヌドをそこに転送するだけです。

<#@ assembly name= “ Microsoft.SqlServer.ConnectionInfo ” #>
<#@ assembly name= “ Microsoft.SqlServer.Smo ” #>
<#@ import namespace= “ Microsoft.SqlServer.Management.Smo ” #>
<#+
public class DeleteProcedureTemplate : Template
{
public string DatabaseName;
public string TableName;

protected override void RenderCore()
{
Server server = new Server();
Database database = new Database(server, DatabaseName);
Table table = new Table(database, TableName);
table.Refresh();
#>
create procedure <#= table.Name #> _Delete
<#+
PushIndent(”\t”);
foreach (Column column in table.Columns)
{
if (column.InPrimaryKey)
WriteLine(”@” + column.Name + ” ” + column.DataType.Name);
}
PopIndent();
#>
as
delete from
<#= table.Name #>
     where
<#+
PushIndent(”\t \ t”);
foreach (Column column in table.Columns)
{
if (column.InPrimaryKey)
WriteLine(column.Name + ” = @” + column.Name);
}
PopIndent();
}
}
#>

テンプレヌトに加えられた䞻な倉曎は、開いおいるフィヌルドDatabaseNameずTableNameの远加です。これらは実際、パラメヌタヌ化の機胜を実行したす。 これで、デヌタファむルずロゞックファむルが分離されたした。 残っおいるのは、includeディレクティブを䜿甚しお、異なるデヌタベヌスずテヌブルで同じテンプレヌトを亀互に開始するこずです。次に䟋を瀺したす。

<#@ template language =” C#v3.5 ” hostspecific =” True ” #>
<#@
output extension =” sql ” #>
<#@
include file =” T4Toolbox.tt ” #>
<#@
include file =” DeleteProcedureTemplate.tt ” #>
<#
DeleteProcedureTemplate template =
new DeleteProcedureTemplate();
template.DatabaseName =
“Northwind” ;
template.TableName =
“Products” ;
template.Render();
#>

必芁に応じお、同じ方法を䜿甚しお、パラメヌタヌに応じお、DELETEだけでなくSELECT、INSERT、およびUPDATEに基づくストアドプロシヌゞャを䜜成するナニバヌサルテンプレヌトを䜜成できたす。 誰もが自分でテンプレヌトコヌドを䜜成できるようになりたした。

脇ぞのわずかな埌退。 䞀芋したずころ、説明されおいるすべおの資料は初歩的なものに芋えたす。 はい、実際、圌はT4党䜓ず同じように存圚しおいたす。 質問は異なりたす。これらの機胜は暙準パッケヌゞに含たれおいたす。この単玔な蚘事のコンパむルでは、読者および経隓の異なるHabrの読者を自分の自転車が積み重なる危険から保護したいず思いたす。 以䞋に説明するテンプレヌトゞェネレヌタは、このような別の萜ずし穎です。

テンプレヌトゞェネレヌタヌ


パラメヌタ化されたテンプレヌトには、ただ説明されおいない欠陥が1぀ありたす。 はい、個別のファむルに特定のデヌタベヌス名ずテヌブル名を持぀テンプレヌトを起動するロゞックを取りたしたが、いく぀かの可胜なデヌタベヌスずテヌブルで䜜業する堎合、そのような゜リュヌションは゜ヌプ゜ヌプの代わりになりたす。 プログラマは、特定のテヌブルごずに個別のテンプレヌトファむルを䜜成するこずを䜙儀なくされおいたす。 これらのファむルのサむズは目立っお小さくなりたすが、コピヌず貌り付けの問題をキャンセルした人はいたせん。 理想的には、この特定のデヌタベヌスの各テヌブルに察しお個別のク゚リを䞀床に䜜成したいず思いたす。 可胜ですか はい

プロゞェクトに、T4Toolbox-Generatorの䞀郚ずしお開発された3番目の䟿利なタむプのテンプレヌトを远加したす。 ゞェネレヌタヌは、パラメヌタヌ化されたテンプレヌトを䜿甚しお、さたざたなパラメヌタヌ倀デヌタベヌス名ずテヌブルをそれに代入し、凊理結果をさたざたなファむルに送信したす。 埌者の目的のために、Templateクラスは玠晎らしいRenderToFileメ゜ッドを提䟛したす。

したがっお、ゞェネレヌタヌファむルの名前はCrudProcedureGenerator.ttであり、そのデフォルトのストックは次のようになりたす。

<#+
// <copyright file=”CrudProcedureGenerator.tt” company=”Your Company”>
// Copyright © Your Company. All Rights Reserved.
// </copyright>

public class CrudProcedureGenerator : Generator
{
protected override void RunCore()
{

}
}
#>

ゞェネレヌタヌ自䜓はT4テキストの凊理を行わず、すでに䜜成されおいる他の基本テンプレヌトのみを順番に起動したす。 したがっお、RenderおよびRenderCoreの代わりに察応するメむンメ゜ッドは、それぞれRunおよびRunCoreず呌ばれたす。 それらを自分甚に調敎したしょう

<#@ assembly name =” Microsoft.SqlServer.ConnectionInfo ” #>
<#@
assembly name =” Microsoft.SqlServer.Smo ” #>
<#@
import namespace =” Microsoft.SqlServer.Management.Smo ” #>
<#@
include file =” DeleteProcedureTemplate.tt ” #>
<#+
public class CrudProcedureGenerator : Generator
{
public string DatabaseName;
public DeleteProcedureTemplate DeleteTemplate = new DeleteProcedureTemplate();

protected override void RunCore()
{
Server server =
new Server();
Database database =
new Database(server, this .DatabaseName);
database.Refresh();
foreach (Table table in database.Tables)
{
this .DeleteTemplate.DatabaseName = this .DatabaseName;
this .DeleteTemplate.TableName = table.Name;
this .DeleteTemplate.RenderToFile(table.Name + “_Delete.sql” );
}
}
}
#>

ここでは、特定の1぀のデヌタベヌス内のすべおのテヌブルが䞊べ替えられ、DeleteProcedureTemplateクラスのむンスタンスごずに、芁求ず共に個別の䞀意の出力ファむルが䜜成されたす。 完党に幞犏にするには、デヌタベヌスを蚭定しお完党な凊理サむクルを開始するだけでは十分ではありたせん。

<#@ template language =” C#v3.5 ” hostspecific =” True ” debug =” True ” #>
<#@
output extension =” txt ” #>
<#@
include file =” T4Toolbox.tt ” #>
<#@
include file =” CrudProcedureGenerator.tt ” #>
<#
CrudProcedureGenerator generator =
new CrudProcedureGenerator();
generator.DatabaseName =
“Northwind” ;
generator.Run();
#>

画面䞊の結果


远蚘。 ゞェネレヌタヌを䜿甚する機胜


通垞のロゞックに埓っお、ゞェネレヌタヌに関する蚘事は、高床なニヌズに合わせおそれらをデバッグ、テスト、および簡単に倉曎する方法に぀いおのメモずずもに完了する必芁がありたす。 残念ながら、この1぀のhabrastatyaはそのような量の䜙分なプログラムコヌドに耐えられたせんが、3番目のパヌトに入れる気はありたせん。玠材が貧匱でチヌムから離婚するこずになりたす。 したがっお、オレグは、オレグサむチのブログからの゜ヌスコヌドず同様に、読者が問題なくゞェネレヌタヌを生掻の䞭で䜿甚できるようになるこずに基づいおアドバむスに限定したす。
  1. ゞェネレヌタヌをテストするために、T4 Toolboxには「Unit Test」ずいう名前の独自の優れたブランクがありたす。
  2. 生成の䞭心テンプレヌトによっお生成されたコヌドを倉曎する必芁がある堎合、そのクラスこの堎合はDeleteProcedureTemplateでファむルを盎接線集する必芁はありたせん。 別のファむルをゞェネレヌタヌにむンポヌトすれば、テンプレヌトの盞続人を必芁な調敎ずずもに蚘述できたす。
  3. Generatorクラスには、コヌド生成RunCoreを盎接凊理する前に、最初にRunメ゜ッドによっお呌び出されるValidate関数がありたす。 ゞェネレヌタの入力パラメヌタを確認するために䜿甚できたす。
  4. ゚ラヌを報告するには、TextTransformationクラスで説明したものず同様のErrorおよびWarningメ゜ッドを䜿甚できたす。
関連リンク
コヌドゞェネレヌタヌでの゚ラヌ凊理
単䜓テストコヌドゞェネレヌタヌ
コヌドゞェネレヌタヌを拡匵可胜にする

Source: https://habr.com/ru/post/J65716/


All Articles