適用対象:SQL Server
Azure SQL Database
Azure SQL Managed Instance
Microsoft Fabric の SQL データベース
このチュートリアルでは、SQL Server のコード分析ルールを作成する手順について説明します。 このチュートリアルで作成するルールは、ストアド プロシージャ、トリガー、および関数で WAITFOR DELAY ステートメントを回避する場合に使用します。
このチュートリアルでは、次の手順を使用して、Transact-SQL の静的コード分析のカスタム ルールを作成します。
- クラス ライブラリ プロジェクトを作成し、そのプロジェクトの署名を有効にして、必要な参照を追加します。
- 2 つのヘルパー C# クラスを作成します。
- C# のカスタム ルール クラスを作成します。
- クラス ライブラリ プロジェクトをビルドします。
- 新しいコード分析ルールをインストールしてテストします。
Visual Studio (SQL Server Data Tools) の手順を除き、このガイドでは SDK スタイルの SQL プロジェクトに焦点を当てています。
Prerequisites
このチュートリアルを実行するには、次のコンポーネントが必要です。
- C# .NET Framework の開発をサポートする、SQL Server Data Tools を含む、インストールされている Visual Studio のバージョン。
- SQL Server オブジェクトを含む SQL Server プロジェクト。
- データベース プロジェクトを配置できる SQL Server のインスタンス。
このチュートリアルは、既に SQL Server Data Tools の SQL Server 機能を使い慣れているユーザーを対象としています。 クラス ライブラリを作成して NuGet パッケージを追加する方法、コード エディターを使用してクラスにコードを追加する方法など、Visual Studio の概念を理解している必要があります。
Note
SDK スタイルの SQL Server Data Tools のプレビュー制限により、このチュートリアルを完了するには複数の Visual Studio インストールが必要です。 クラス ライブラリ プロジェクトを作成するには最初のインストールが必要です。SDK スタイルの SQL データベース プロジェクトを作成するには 2 番目のインストールが必要です。
- .NET 8 SDK
- Visual Studio 2022 Community、Professional、Enterprise のいずれか
- Visual Studio 2022 にインストールされた SQL Server Data Tools、SDK スタイル (プレビュー)
- C# .NET 開発をサポートする、インストールされている Visual Studio のバージョン。
- SQL Server オブジェクトを含む SQL Server プロジェクト。
このチュートリアルは、既に SQL Server Data Tools の SQL Server 機能を使い慣れているユーザーを対象としています。 クラス ライブラリを作成して NuGet パッケージを追加する方法、コード エディターを使用してクラスにコードを追加する方法など、Visual Studio の概念を理解している必要があります。
- インストールされている Visual Studio Code のバージョン。SQL Database プロジェクト拡張機能が含まれます。
- SQL オブジェクトを含む SQL Database プロジェクト。
- .NET 8 SDK
- 推奨: VS Code の C# 開発キット拡張機能
このチュートリアルは、Visual Studio Code の SQL Database プロジェクト拡張機能に既に慣れているユーザーを対象としています。 クラス ライブラリを作成してパッケージを追加する方法、コード エディターを使用してコードを編集する方法など、開発の概念を理解している必要があります。
- テキスト エディター (Visual Studio Code のファイル エディターなど)。
- SQL オブジェクトを含む SQL Database プロジェクト。
- .NET 8 SDK
このチュートリアルは、既に SQL プロジェクトを使い慣れているユーザーを対象としています。 クラス ライブラリを作成してパッケージを追加する方法、コード エディターを使用してコードを編集する方法など、開発の概念を理解している必要があります。
手順 1 - クラス ライブラリ プロジェクトを作成する
まずクラス ライブラリを作成します。 クラス ライブラリ プロジェクトを作成するには、次の操作を行います。
SampleRulesという名前の C# (.NET Framework) クラス ライブラリ プロジェクトを作成します。ファイルの名前を
Class1.csからAvoidWaitForDelayRule.csに変更します。ソリューション エクスプローラーで、プロジェクト ノードを右クリックし、[追加]、[参照] の順に選択します。
System.ComponentModel.Compositionタブで を選択します。ソリューション エクスプローラーで、プロジェクト ノードを右クリックし、[NuGet パッケージの管理] を選択します。
Microsoft.SqlServer.DacFxNuGet パッケージを見つけてインストールします。 選択したバージョンは、Visual Studio 2022 の場合 (たとえば162.x.x)162.2.111である必要があります。
次に、ルールに使用するサポート クラスを追加します。
まずクラス ライブラリを作成します。 クラス ライブラリ プロジェクトを作成するには、次の操作を行います。
SampleRulesという名前の C# (.NET Framework) クラス ライブラリ プロジェクトを作成します。ファイルの名前を
Class1.csからAvoidWaitForDelayRule.csに変更します。ソリューション エクスプローラーで、プロジェクト ノードを右クリックし、[追加]、[参照] の順に選択します。
System.ComponentModel.Compositionタブで を選択します。ソリューション エクスプローラーで、プロジェクト ノードを右クリックし、[NuGet パッケージの管理] を選択します。
Microsoft.SqlServer.DacFxNuGet パッケージを見つけてインストールします。 選択したバージョンは、Visual Studio 2022 の場合 (たとえば162.x.x)162.2.111である必要があります。
次に、ルールに使用するサポート クラスを追加します。
Visual Studio Code を起動し、プロジェクトを作成するフォルダーを開きます。
Visual Studio Code 内で、[表示] メニュー、次に [ターミナル] を選択してターミナル ウィンドウを開きます。
[ターミナル] で、次のコマンドを入力して、新しいソリューションとプロジェクトを作成します。
dotnet new sln dotnet new classlib -n SampleRules -o SampleRules dotnet sln add SampleRules/SampleRules.csprojSampleRulesディレクトリに変更します。cd SampleRules必要な NuGet パッケージを追加します。
dotnet add package Microsoft.SqlServer.DacFx
次に、ルールに使用するサポート クラスを追加します。
コマンド プロンプトまたはターミナル ウィンドウを開き、プロジェクトを作成するフォルダーに移動します。
[ターミナル] で、次のコマンドを入力して、新しいソリューションとプロジェクトを作成します。
dotnet new sln dotnet new classlib -n SampleRules -o SampleRules dotnet sln add SampleRules/SampleRules.csprojSampleRulesディレクトリに変更します。cd SampleRules必要な NuGet パッケージを追加します。
dotnet add package Microsoft.SqlServer.DacFx
手順 2: カスタム ルール ヘルパー クラスを作成する
ルール用のクラスを作成する前に、ビジター クラスと属性クラスをプロジェクトに追加します。 これらのクラスは、追加のカスタム ルールを作成するときに便利なことがあります。
手順 2.1: WaitForDelayVisitor クラスを定義する
最初に定義する必要があるクラスは、WaitForDelayVisitor クラスです。このクラスは、TSqlConcreteFragmentVisitor から派生します。 このクラスを使用すると、モデル内の WAITFOR DELAY ステートメントにアクセスできます。 ビジター クラスは、SQL Server で提供される ScriptDom API を利用します。 この API の Transact-SQL コードは、抽象構文ツリー (AST) として表されます。ビジター クラスは、WAITFOR DELAY ステートメントなど、特定の構文オブジェクトを探すときに便利です。 これらの構文オブジェクトは、特定のオブジェクト プロパティや関係に関連付けられていないので、オブジェクト モデルを使用して見つけるのは難しいことがありますが、ビジター パターンと ScriptDom API を使用して見つけることができます。
ソリューション エクスプローラーで
SampleRulesプロジェクトを選択します。[プロジェクト] メニューで、[クラスの追加] を選択します。 [新しい項目の追加] ダイアログ ボックスが表示されます。 [名前] テキスト ボックスに「
WaitForDelayVisitor.cs」と入力し、[追加] を選択します。WaitForDelayVisitor.csファイルは、[ソリューション エクスプローラー] のプロジェクトに追加されます。
ソリューション エクスプローラーで
SampleRulesプロジェクトを選択します。[プロジェクト] メニューで、[クラスの追加] を選択します。 [新しい項目の追加] ダイアログ ボックスが表示されます。 [名前] テキスト ボックスに「
WaitForDelayVisitor.cs」と入力し、[追加] を選択します。WaitForDelayVisitor.csファイルは、[ソリューション エクスプローラー] のプロジェクトに追加されます。
Visual Studio Code で[エクスプローラー] ビューを開きます。
WaitForDelayVisitor.csフォルダーに、SampleRulesという名前の新しいファイルを作成します。
-
SampleRulesディレクトリに移動します。 -
WaitForDelayVisitor.csという名前で新しいファイルを作成します。
WaitForDelayVisitor.csファイルを開き、次のコードに合わせて内容を更新します。using System.Collections.Generic; using Microsoft.SqlServer.TransactSql.ScriptDom; namespace SampleRules { class WaitForDelayVisitor {} }クラス宣言で、アクセス修飾子を internal に変更し、
TSqlConcreteFragmentVisitorからクラスを派生させます。internal class WaitForDelayVisitor : TSqlConcreteFragmentVisitor {}次のコードを追加して、List メンバー変数を定義します。
public IList<WaitForStatement> WaitForDelayStatements { get; private set; }次のコードを追加して、クラス コンストラクターを定義します。
public WaitForDelayVisitor() { WaitForDelayStatements = new List<WaitForStatement>(); }次のコードを追加して、
ExplicitVisitメソッドをオーバーライドします。public override void ExplicitVisit(WaitForStatement node) { // We are only interested in WAITFOR DELAY occurrences if (node.WaitForOption == WaitForOption.Delay) WaitForDelayStatements.Add(node); }このメソッドは、モデル内の
WAITFORステートメントにアクセスし、DELAYオプションを指定したステートメントをWAITFOR DELAYステートメントの一覧に追加します。 参照するキー クラスは、WaitForStatement です。[ファイル] メニューの [保存] をクリックします。
手順 2.2: リソース ファイルと 3 つのリソース文字列を追加する
次に、ルール名、ルールの説明、およびカテゴリを定義したリソース ファイルを追加します。このルールは、ルール構成インターフェイスに表示されます。
ソリューション エクスプローラーで
SampleRulesプロジェクトを選択します。 [プロジェクト] メニューで、[追加]、[新しい項目] の順に選択します。 [新しい項目の追加] ダイアログ ボックスが表示されます。[インストールされたテンプレート] の一覧で、[全般] を選択します。 詳細ウィンドウの [リソース ファイル] を選択します。
[名前]に「
RuleResources.resx」と入力します。 リソースが定義されていないリソース エディターが表示されます。次のように、4 つのリソース文字列を定義します。
Name Value AvoidWaitForDelay_ProblemDescriptionWAITFOR DELAY statement was found in {0}.AvoidWaitForDelay_RuleNameAvoid using WaitFor Delay statements in stored procedures, functions and triggers.CategorySamplesSamplesCategoryCannotCreateResourceManagerCan't create ResourceManager for {0} from {1}.[ファイル] メニューで、[RuleResources.resx の保存] を選択します。
ソリューション エクスプローラーで
SampleRulesプロジェクトを選択します。 [プロジェクト] メニューで、[追加]、[新しい項目] の順に選択します。 [新しい項目の追加] ダイアログ ボックスが表示されます。[インストールされたテンプレート] の一覧で、[全般] を選択します。 詳細ウィンドウの [リソース ファイル] を選択します。
[名前]に「
RuleResources.resx」と入力します。 リソースが定義されていないリソース エディターが表示されます。次のように、4 つのリソース文字列を定義します。
Name Value AvoidWaitForDelay_ProblemDescriptionWAITFOR DELAY statement was found in {0}.AvoidWaitForDelay_RuleNameAvoid using WaitFor Delay statements in stored procedures, functions and triggers.CategorySamplesSamplesCategoryCannotCreateResourceManagerCan't create ResourceManager for {0} from {1}.[ファイル] メニューで、[RuleResources.resx の保存] を選択します。
SampleRulesディレクトリにRuleResources.resxという名前の新しいファイルを作成します。RuleResources.resxファイルを開き、次のコードを追加します。<?xml version="1.0" encoding="utf-8"?> <root> <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> <xsd:import namespace="http://www.w3.org/XML/1998/namespace" /> <xsd:element name="root" msdata:IsDataSet="true"> <xsd:complexType> <xsd:choice maxOccurs="unbounded"> <xsd:element name="metadata"> <xsd:complexType> <xsd:sequence> <xsd:element name="value" type="xsd:string" minOccurs="0" /> </xsd:sequence> <xsd:attribute name="name" use="required" type="xsd:string" /> <xsd:attribute name="type" type="xsd:string" /> <xsd:attribute name="mimetype" type="xsd:string" /> <xsd:attribute ref="xml:space" /> </xsd:complexType> </xsd:element> <xsd:element name="assembly"> <xsd:complexType> <xsd:attribute name="alias" type="xsd:string" /> <xsd:attribute name="name" type="xsd:string" /> </xsd:complexType> </xsd:element> <xsd:element name="data"> <xsd:complexType> <xsd:sequence> <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> </xsd:sequence> <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" /> <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> <xsd:attribute ref="xml:space" /> </xsd:complexType> </xsd:element> <xsd:element name="resheader"> <xsd:complexType> <xsd:sequence> <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> </xsd:sequence> <xsd:attribute name="name" type="xsd:string" use="required" /> </xsd:complexType> </xsd:element> </xsd:choice> </xsd:complexType> </xsd:element> </xsd:schema> <resheader name="resmimetype"> <value>text/microsoft-resx</value> </resheader> <resheader name="version"> <value>2.0</value> </resheader> <resheader name="reader"> <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> </resheader> <resheader name="writer"> <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> </resheader> <data name="AvoidWaitForDelay_ProblemDescription" xml:space="preserve"> <value>WAITFOR DELAY statement was found in {0}</value> </data> <data name="AvoidWaitFormDelay_RuleName" xml:space="preserve"> <value>Avoid using WaitFor Delay statements in stored procedures, functions and triggers.</value> </data> <data name="CategorySamples" xml:space="preserve"> <value>SamplesCategory</value> </data> <data name="CannotCreateResourceManager" xml:space="preserve"> <value>Can't create ResourceManager for {0} from {1}</value> </data> </root>RuleResources.resxファイルを保存します。SampleRules.csprojファイルを開き、次のコードを追加して更新し、リソースの内容をプロジェクトに含めます。<ItemGroup> <Compile Update="RuleResources.Designer.cs"> <DesignTime>True</DesignTime> <AutoGen>True</AutoGen> <DependentUpon>RuleResources.resx</DependentUpon> </Compile> </ItemGroup> <ItemGroup> <EmbeddedResource Include="RuleResources.resx"> <Generator>PublicResXFileCodeGenerator</Generator> <LastGenOutput>RuleResources.Designer.cs</LastGenOutput> </EmbeddedResource> </ItemGroup>SampleRules.csprojファイルを保存します。
SampleRulesディレクトリにRuleResources.resxという名前の新しいファイルを作成します。RuleResources.resxファイルを開き、次のコードを追加します。<?xml version="1.0" encoding="utf-8"?> <root> <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> <xsd:import namespace="http://www.w3.org/XML/1998/namespace" /> <xsd:element name="root" msdata:IsDataSet="true"> <xsd:complexType> <xsd:choice maxOccurs="unbounded"> <xsd:element name="metadata"> <xsd:complexType> <xsd:sequence> <xsd:element name="value" type="xsd:string" minOccurs="0" /> </xsd:sequence> <xsd:attribute name="name" use="required" type="xsd:string" /> <xsd:attribute name="type" type="xsd:string" /> <xsd:attribute name="mimetype" type="xsd:string" /> <xsd:attribute ref="xml:space" /> </xsd:complexType> </xsd:element> <xsd:element name="assembly"> <xsd:complexType> <xsd:attribute name="alias" type="xsd:string" /> <xsd:attribute name="name" type="xsd:string" /> </xsd:complexType> </xsd:element> <xsd:element name="data"> <xsd:complexType> <xsd:sequence> <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> </xsd:sequence> <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" /> <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> <xsd:attribute ref="xml:space" /> </xsd:complexType> </xsd:element> <xsd:element name="resheader"> <xsd:complexType> <xsd:sequence> <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> </xsd:sequence> <xsd:attribute name="name" type="xsd:string" use="required" /> </xsd:complexType> </xsd:element> </xsd:choice> </xsd:complexType> </xsd:element> </xsd:schema> <resheader name="resmimetype"> <value>text/microsoft-resx</value> </resheader> <resheader name="version"> <value>2.0</value> </resheader> <resheader name="reader"> <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> </resheader> <resheader name="writer"> <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> </resheader> <data name="AvoidWaitForDelay_ProblemDescription" xml:space="preserve"> <value>WAITFOR DELAY statement was found in {0}</value> </data> <data name="AvoidWaitFormDelay_RuleName" xml:space="preserve"> <value>Avoid using WaitFor Delay statements in stored procedures, functions and triggers.</value> </data> <data name="CategorySamples" xml:space="preserve"> <value>SamplesCategory</value> </data> <data name="CannotCreateResourceManager" xml:space="preserve"> <value>Can't create ResourceManager for {0} from {1}</value> </data> </root>RuleResources.resxファイルを保存します。SampleRules.csprojファイルを開き、次のコードを追加して更新し、リソースの内容をプロジェクトに含めます。<ItemGroup> <Compile Update="RuleResources.Designer.cs"> <DesignTime>True</DesignTime> <AutoGen>True</AutoGen> <DependentUpon>RuleResources.resx</DependentUpon> </Compile> </ItemGroup> <ItemGroup> <EmbeddedResource Include="RuleResources.resx"> <Generator>PublicResXFileCodeGenerator</Generator> <LastGenOutput>RuleResources.Designer.cs</LastGenOutput> </EmbeddedResource> </ItemGroup>SampleRules.csprojファイルを保存します。
手順 2.3: LocalizedExportCodeAnalysisRuleAttribute クラスを定義する
2 つ目のクラスは、LocalizedExportCodeAnalysisRuleAttribute.cs です。 これはフレームワークによって提供される組み込みの Microsoft.SqlServer.Dac.CodeAnalysis.ExportCodeAnalysisRuleAttribute の拡張機能であり、リソース ファイルからのルールによって使用される DisplayName と Description の読み取りをサポートします。 このクラスは、複数の言語でルールを使用する予定がある場合に便利です。
ソリューション エクスプローラーで
SampleRulesプロジェクトを選択します。[プロジェクト] メニューで、[クラスの追加] を選択します。 [新しい項目の追加] ダイアログ ボックスが表示されます。 [名前] テキスト ボックスに「
LocalizedExportCodeAnalysisRuleAttribute.cs」と入力し、[追加] を選択します。 ファイルは、ソリューション エクスプローラーのプロジェクトに追加されます。
ソリューション エクスプローラーで
SampleRulesプロジェクトを選択します。[プロジェクト] メニューで、[クラスの追加] を選択します。 [新しい項目の追加] ダイアログ ボックスが表示されます。 [名前] テキスト ボックスに「
LocalizedExportCodeAnalysisRuleAttribute.cs」と入力し、[追加] を選択します。 ファイルは、ソリューション エクスプローラーのプロジェクトに追加されます。
- Visual Studio Code の
SampleRulesビューで ディレクトリに移動します。 -
LocalizedExportCodeAnalysisRuleAttribute.csという名前で新しいファイルを作成します。
-
SampleRulesディレクトリに移動します。 -
LocalizedExportCodeAnalysisRuleAttribute.csという名前で新しいファイルを作成します。
ファイルを開き、次のコードに合わせて内容を更新します。
using Microsoft.SqlServer.Dac.CodeAnalysis; using System; using System.Globalization; using System.Reflection; using System.Resources; namespace SampleRules { internal class LocalizedExportCodeAnalysisRuleAttribute : ExportCodeAnalysisRuleAttribute { private readonly string _resourceBaseName; private readonly string _displayNameResourceId; private readonly string _descriptionResourceId; private ResourceManager _resourceManager; private string _displayName; private string _descriptionValue; /// <summary> /// Creates the attribute, with the specified rule ID, the fully qualified /// name of the resource file that will be used for looking up display name /// and description, and the Ids of those resources inside the resource file. /// </summary> public LocalizedExportCodeAnalysisRuleAttribute( string id, string resourceBaseName, string displayNameResourceId, string descriptionResourceId) : base(id, null) { _resourceBaseName = resourceBaseName; _displayNameResourceId = displayNameResourceId; _descriptionResourceId = descriptionResourceId; } /// <summary> /// Rules in a different assembly would need to overwrite this /// </summary> /// <returns></returns> protected virtual Assembly GetAssembly() { return GetType().Assembly; } private void EnsureResourceManagerInitialized() { var resourceAssembly = GetAssembly(); try { _resourceManager = new ResourceManager(_resourceBaseName, resourceAssembly); } catch (Exception ex) { var msg = String.Format(CultureInfo.CurrentCulture, RuleResources.CannotCreateResourceManager, _resourceBaseName, resourceAssembly); throw new RuleException(msg, ex); } } private string GetResourceString(string resourceId) { EnsureResourceManagerInitialized(); return _resourceManager.GetString(resourceId, CultureInfo.CurrentUICulture); } /// <summary> /// Overrides the standard DisplayName and looks up its value inside a resources file /// </summary> public override string DisplayName { get { if (_displayName == null) { _displayName = GetResourceString(_displayNameResourceId); } return _displayName; } } /// <summary> /// Overrides the standard Description and looks up its value inside a resources file /// </summary> public override string Description { get { if (_descriptionValue == null) { _descriptionValue = GetResourceString(_descriptionResourceId); } return _descriptionValue; } } } }
手順 2.4: SampleConstants クラスを定義する
次に、ユーザー インターフェイスにルールに関する情報を表示するときに Visual Studio で使用されるリソース ファイル内のリソースを参照するクラスを定義します。
ソリューション エクスプローラーで
SampleRulesプロジェクトを選択します。[プロジェクト] メニューで、[追加]、[クラス] の順に選択します。 [新しい項目の追加] ダイアログ ボックスが表示されます。 [名前] テキスト ボックスに「
SampleRuleConstants.cs」と入力し、[追加] ボタンを選択します。SampleRuleConstants.csファイルは、[ソリューション エクスプローラー] のプロジェクトに追加されます。
ソリューション エクスプローラーで
SampleRulesプロジェクトを選択します。[プロジェクト] メニューで、[追加]、[クラス] の順に選択します。 [新しい項目の追加] ダイアログ ボックスが表示されます。 [名前] テキスト ボックスに「
SampleRuleConstants.cs」と入力し、[追加] ボタンを選択します。SampleRuleConstants.csファイルは、[ソリューション エクスプローラー] のプロジェクトに追加されます。
- Visual Studio Code の
SampleRulesビューで ディレクトリに移動します。 -
SampleRuleConstants.csという名前で新しいファイルを作成します。
-
SampleRulesディレクトリに移動します。 -
SampleRuleConstants.csという名前で新しいファイルを作成します。
SampleRuleConstants.csファイルを開き、次の using ステートメントをファイルに追加します。namespace SampleRules { internal static class RuleConstants { /// <summary> /// The name of the resources file to use when looking up rule resources /// </summary> public const string ResourceBaseName = "SampleRules.RuleResources"; /// <summary> /// Lookup name inside the resources file for the select asterisk rule name /// </summary> public const string AvoidWaitForDelay_RuleName = "AvoidWaitForDelay_RuleName"; /// <summary> /// Lookup ID inside the resources file for the select asterisk description /// </summary> public const string AvoidWaitForDelay_ProblemDescription = "AvoidWaitForDelay_ProblemDescription"; /// <summary> /// The design category (should not be localized) /// </summary> public const string CategoryDesign = "Design"; /// <summary> /// The performance category (should not be localized) /// </summary> public const string CategoryPerformance = "Design"; } }[ファイル] メニューの [保存] をクリックします。
手順 3: カスタム ルール クラスを作成する
カスタム コード分析ルールで使用するヘルパー クラスを追加したら、カスタム ルール クラスを作成し、AvoidWaitForDelayRule という名前を付けます。 データベースの開発時に、AvoidWaitForDelayRule カスタム ルールを使用すると、ストアド プロシージャ、トリガー、および関数で WAITFOR DELAY ステートメントを回避できます。
手順 3.1: AvoidWaitForDelayRule クラスを作成する
ソリューション エクスプローラーで
SampleRulesプロジェクトを選択します。[プロジェクト] メニューで、[追加]、[クラス] の順に選択します。 [新しい項目の追加] ダイアログ ボックスが表示されます。 [名前] テキスト ボックスに「
AvoidWaitForDelayRule.cs」と入力し、[追加] を選択します。AvoidWaitForDelayRule.csファイルは、[ソリューション エクスプローラー] のプロジェクトに追加されます。
ソリューション エクスプローラーで
SampleRulesプロジェクトを選択します。[プロジェクト] メニューで、[追加]、[クラス] の順に選択します。 [新しい項目の追加] ダイアログ ボックスが表示されます。 [名前] テキスト ボックスに「
AvoidWaitForDelayRule.cs」と入力し、[追加] を選択します。AvoidWaitForDelayRule.csファイルは、[ソリューション エクスプローラー] のプロジェクトに追加されます。
- Visual Studio Code の
SampleRulesビューで ディレクトリに移動します。 -
AvoidWaitForDelayRule.csという名前で新しいファイルを作成します。
-
SampleRulesディレクトリに移動します。 -
AvoidWaitForDelayRule.csという名前で新しいファイルを作成します。
AvoidWaitForDelayRule.csファイルを開き、次の using ステートメントをファイルに追加します。using Microsoft.SqlServer.Dac.CodeAnalysis; using Microsoft.SqlServer.Dac.Model; using Microsoft.SqlServer.TransactSql.ScriptDom; using System; using System.Collections.Generic; using System.Globalization; namespace SampleRules { class AvoidWaitForDelayRule {} }AvoidWaitForDelayRuleクラス宣言で、アクセス修飾子を public に変更します。/// <summary> /// This is a rule that returns a warning message /// whenever there is a WAITFOR DELAY statement appears inside a subroutine body. /// This rule only applies to stored procedures, functions and triggers. /// </summary> public sealed class AvoidWaitForDelayRuleAvoidWaitForDelayRuleクラスは、Microsoft.SqlServer.Dac.CodeAnalysis.SqlCodeAnalysisRule基本クラスから派生します。public sealed class AvoidWaitForDelayRule : SqlCodeAnalysisRuleクラスに
LocalizedExportCodeAnalysisRuleAttributeを追加します。LocalizedExportCodeAnalysisRuleAttributeを使用すると、コード分析サービスでカスタム コード分析ルールを検出できます。 コード分析では、ExportCodeAnalysisRuleAttribute(またはこの属性から継承している属性) でマークしたクラスのみを使用できます。LocalizedExportCodeAnalysisRuleAttributeは、サービスで使用される必要なメタデータを提供します。 たとえば、このルールの一意の ID、Visual Studio ユーザー インターフェイスに表示される表示名、問題を特定するときにルールに使用できるDescriptionなどです。[LocalizedExportCodeAnalysisRule(AvoidWaitForDelayRule.RuleId, RuleConstants.ResourceBaseName, RuleConstants.AvoidWaitForDelay_RuleName, RuleConstants.AvoidWaitForDelay_ProblemDescription Category = RuleConstants.CategoryPerformance, RuleScope = SqlRuleScope.Element)] public sealed class AvoidWaitForDelayRule : SqlCodeAnalysisRule { /// <summary> /// The Rule ID should resemble a fully-qualified class name. In the Visual Studio UI /// rules are grouped by "Namespace + Category", and each rule is shown using "Short ID: DisplayName". /// For this rule, that means the grouping will be "Public.Dac.Samples.Performance", with the rule /// shown as "SR1004: Avoid using WaitFor Delay statements in stored procedures, functions and triggers." /// </summary> public const string RuleId = "RuleSamples.SR1004"; }RuleScope プロパティは、このルールが特定の要素を分析するため、
Microsoft.SqlServer.Dac.CodeAnalysis.SqlRuleScope.Elementである必要があります。 このルールは、モデル内の一致する要素ごとに 1 回呼び出されます。 モデル全体を分析する場合は、代わりにMicrosoft.SqlServer.Dac.CodeAnalysis.SqlRuleScope.Modelを使用できます。Microsoft.SqlServer.Dac.CodeAnalysis.SqlAnalysisRule.SupportedElementTypesを設定するコンストラクターを追加します。 要素がスコープのルールの場合は必須です。 このルールが適用される要素の種類を定義します。 この場合、ルールはストアド プロシージャ、トリガー、および関数に適用されます。Microsoft.SqlServer.Dac.Model.ModelSchemaクラスには、分析可能なすべての要素の種類が一覧表示されます。public AvoidWaitForDelayRule() { // This rule supports Procedures, Functions and Triggers. Only those objects will be passed to the Analyze method SupportedElementTypes = new[] { // Note: can use the ModelSchema definitions, or access the TypeClass for any of these types ModelSchema.ExtendedProcedure, ModelSchema.Procedure, ModelSchema.TableValuedFunction, ModelSchema.ScalarFunction, ModelSchema.DatabaseDdlTrigger, ModelSchema.DmlTrigger, ModelSchema.ServerDdlTrigger }; }入力パラメーターとして
Microsoft.SqlServer.Dac.CodeAnalysis.SqlAnalysisRule.Analyzeを使用する(Microsoft.SqlServer.Dac.CodeAnalysis.SqlRuleExecutionContext)Microsoft.SqlServer.Dac.CodeAnalysis.SqlRuleExecutionContextメソッドのオーバーライドを追加します。 このメソッドは、可能性のある問題の一覧を返します。メソッドは、コンテキスト パラメーターから 、
Microsoft.SqlServer.Dac.Model.TSqlModel、Microsoft.SqlServer.Dac.Model.TSqlObject、および TSqlFragment を取得します。 次に、モデル内のすべてのWaitForDelayVisitorステートメントの一覧を取得するために、WAITFOR DELAYクラスが使用されます。そのリスト内の WaitForStatement ごとに、
Microsoft.SqlServer.Dac.CodeAnalysis.SqlRuleProblemが作成されます。/// <summary> /// For element-scoped rules the Analyze method is executed once for every matching /// object in the model. /// </summary> /// <param name="ruleExecutionContext">The context object contains the TSqlObject being /// analyzed, a TSqlFragment /// that's the AST representation of the object, the current rule's descriptor, and a /// reference to the model being /// analyzed. /// </param> /// <returns>A list of problems should be returned. These will be displayed in the Visual /// Studio error list</returns> public override IList<SqlRuleProblem> Analyze( SqlRuleExecutionContext ruleExecutionContext) { IList<SqlRuleProblem> problems = new List<SqlRuleProblem>(); TSqlObject modelElement = ruleExecutionContext.ModelElement; // this rule does not apply to inline table-valued function // we simply do not return any problem in that case. if (IsInlineTableValuedFunction(modelElement)) { return problems; } string elementName = GetElementName(ruleExecutionContext, modelElement); // The rule execution context has all the objects we'll need, including the // fragment representing the object, // and a descriptor that lets us access rule metadata TSqlFragment fragment = ruleExecutionContext.ScriptFragment; RuleDescriptor ruleDescriptor = ruleExecutionContext.RuleDescriptor; // To process the fragment and identify WAITFOR DELAY statements we will use a // visitor WaitForDelayVisitor visitor = new WaitForDelayVisitor(); fragment.Accept(visitor); IList<WaitForStatement> waitforDelayStatements = visitor.WaitForDelayStatements; // Create problems for each WAITFOR DELAY statement found // When creating a rule problem, always include the TSqlObject being analyzed. This // is used to determine // the name of the source this problem was found in and a best guess as to the // line/column the problem was found at. // // In addition if you have a specific TSqlFragment that is related to the problem //also include this // since the most accurate source position information (start line and column) will // be read from the fragment foreach (WaitForStatement waitForStatement in waitforDelayStatements) { SqlRuleProblem problem = new SqlRuleProblem( String.Format(CultureInfo.CurrentCulture, ruleDescriptor.DisplayDescription, elementName), modelElement, waitForStatement); problems.Add(problem); } return problems; } private static string GetElementName( SqlRuleExecutionContext ruleExecutionContext, TSqlObject modelElement) { // Get the element name using the built in DisplayServices. This provides a number of // useful formatting options to // make a name user-readable var displayServices = ruleExecutionContext.SchemaModel.DisplayServices; string elementName = displayServices.GetElementName( modelElement, ElementNameStyle.EscapedFullyQualifiedName); return elementName; } private static bool IsInlineTableValuedFunction(TSqlObject modelElement) { return TableValuedFunction.TypeClass.Equals(modelElement.ObjectType) && FunctionType.InlineTableValuedFunction == modelElement.GetMetadata<FunctionType>(TableValuedFunction.FunctionType); }[ファイル] メニューの [保存]をクリックします。
手順 4: クラス ライブラリをビルドする
- [プロジェクト] メニューの [SampleRules のプロパティ] を選択します。
- [署名] タブを選択します
- [アセンブリの署名] を選択します。
- [厳密な名前のキー ファイルを選択してください] で <[新規作成]> を選択します。
-
[厳密な名前キーの作成] ダイアログ ボックスで、[キー ファイル] に「
MyRefKey」と入力します。 - (省略可能) 厳密な名前のキー ファイルにパスワードを指定できます。
- [OK] を選択.
- [ファイル] メニューの [すべてを保存] をクリックします。
- [ビルド] メニューの [ソリューションのビルド] を選択します。
- [プロジェクト] メニューの [SampleRules のプロパティ] を選択します。
- [署名] タブを選択します
- [アセンブリの署名] を選択します。
- [厳密な名前のキー ファイルを選択してください] で <[新規作成]> を選択します。
-
[厳密な名前キーの作成] ダイアログ ボックスで、[キー ファイル] に「
MyRefKey」と入力します。 - (省略可能) 厳密な名前のキー ファイルにパスワードを指定できます。
- [OK] を選択.
- [ファイル] メニューの [すべてを保存] をクリックします。
- [ビルド] メニューの [ソリューションのビルド] を選択します。
Visual Studio Code 内で、[表示] メニュー、次に [ターミナル] を選択してターミナル ウィンドウを開きます。
[ターミナル] で次のコマンドを入力して、プロジェクトをビルドします。
dotnet build /p:Configuration=Release
SampleRulesディレクトリに移動します。次のコマンドを実行してプロジェクトをビルドします。
dotnet build /p:Configuration=Release
手順 5: 新しいコード分析ルールをインストールしてテストする
次に、アセンブリをインストールし、SQL Database プロジェクトをビルドするときに読み込まれるようにします。
Visual Studio で元の SQL プロジェクトをビルドするときに実行されるルールをインストールするには、アセンブリと関連付けられている .pdb ファイルを拡張機能フォルダーにコピーする必要があります。
手順 5.1: SampleRules アセンブリをインストールする
- 次に、アセンブリ情報を Extensions ディレクトリにコピーします。 Visual Studio が起動すると、
<Visual Studio Install Dir>\Common7\IDE\Extensions\Microsoft\SQLDB\DAC\Extensionsディレクトリとサブディレクトリの機能拡張が特定され、使用できるようになります。 Visual Studio 2022 の場合、<Visual Studio Install Dir>は通常C:\Program Files\Microsoft Visual Studio\2022\Enterpriseです。 インストールした Visual Studio のエディションに応じて、EnterpriseをProfessionalまたはCommunityに置き換えます。 -
SampleRules.dllアセンブリ ファイルを出力ディレクトリから<Visual Studio Install Dir>\Common7\IDE\Extensions\Microsoft\SQLDB\DAC\Extensionsディレクトリにコピーします。 既定では、コンパイル済みの.dllファイルのパスはYourSolutionPath\YourProjectPath\bin\DebugまたはYourSolutionPath\YourProjectPath\bin\Releaseです。
Note
Extensions ディレクトリを作成する必要がある場合があります。
以上でルールのインストールは完了です。Visual Studio を再起動すると、ルールが表示されます。 次に、Visual Studio の新しいセッションを開始して、データベース プロジェクトを作成します。
手順 5.2: 新しい Visual Studio セッションを開始して、データベース プロジェクトを作成する
- Visual Studio の 2 つ目のセッションを開始します。
- [ファイル]>[新規作成]>[プロジェクト] の順に選択します。
- [新しいプロジェクト] ダイアログ ボックスで、[SQL Server データベース プロジェクト] を見つけて選択します。
-
[名前] テキスト ボックスに「
SampleRulesDB」と入力し、[OK] を選択します。
手順 5.3: AvoidWaitForRule コード分析ルールを有効にする
-
ソリューション エクスプローラーで
SampleRulesDBプロジェクトを選択します。 -
[プロジェクト] メニューの [プロパティ] を選択します。
SampleRulesDBプロパティ ページが表示されます。 -
[コード分析] を選択します。
RuleSamples.CategorySamplesという名前の新しいカテゴリが表示されます。 -
RuleSamples.CategorySamplesを展開します。SR1004: Avoid WAITFOR DELAY statement in stored procedures, triggers, and functionsという結果が表示されます。 - このルールを有効にするには、ルール名の横にあるチェックボックスと、[ビルド時にコード分析を有効にする] のチェックボックスをオンにします。 コード分析を有効にする方法の詳細については、「コード分析の概要」を確認してください。
- プロジェクト [ビルド] アクションが使用されると、ルールが実行され、検出されたすべての
WAITFOR DELAYステートメントが警告として報告されます。
Visual Studio で元の SQL プロジェクトをビルドするときに実行されるルールをインストールするには、アセンブリと関連付けられている .pdb ファイルを拡張機能フォルダーにコピーする必要があります。
手順 5.1: SampleRules アセンブリをインストールする
- 次に、アセンブリ情報を Extensions ディレクトリにコピーします。 Visual Studio が起動すると、
<Visual Studio Install Dir>\Common7\IDE\Extensions\Microsoft\SQLDB\DAC\Extensionsディレクトリとサブディレクトリの機能拡張が特定され、使用できるようになります。 Visual Studio 2022 の場合、<Visual Studio Install Dir>は通常C:\Program Files\Microsoft Visual Studio\2022\Enterpriseです。 インストールされている Visual Studio エディションに応じて、EnterpriseをProfessionalまたはCommunityと置き換えます。 -
SampleRules.dllアセンブリ ファイルを出力ディレクトリから<Visual Studio Install Dir>\Common7\IDE\Extensions\Microsoft\SQLDB\DAC\Extensionsディレクトリにコピーします。 既定では、コンパイル済みの.dllファイルのパスはYourSolutionPath\YourProjectPath\bin\DebugまたはYourSolutionPath\YourProjectPath\bin\Releaseです。
Note
Extensions ディレクトリを作成する必要がある場合があります。
以上でルールのインストールは完了です。Visual Studio を再起動すると、ルールが表示されます。 次に、Visual Studio の新しいセッションを開始して、データベース プロジェクトを作成します。
手順 5.2: 新しい Visual Studio セッションを開始して、データベース プロジェクトを作成する
- Visual Studio の 2 つ目のセッションを開始します。
- [ファイル]>[新規作成]>[プロジェクト] の順に選択します。
- [新しいプロジェクト] ダイアログ ボックスで、[SQL Server データベース プロジェクト、SDK スタイル (プレビュー)] を見つけて選択します。
-
[名前] テキスト ボックスに「
SampleRulesDB」と入力し、[OK] を選択します。
手順 5.3: AvoidWaitForRule コード分析ルールを有効にする
手順 5.1: SampleRules アセンブリをローカル NuGet ソースに配置する
- NuGet パッケージのローカル ソースがない場合は、ローカル テスト用の NuGet パッケージを格納するフォルダーをローカル コンピューターに追加します。 次のコマンドを実行して、現在の NuGet ソースを確認できます。
dotnet nuget list source
- ローカル ソースが一覧にない場合は、次のコマンドを使用して追加できます。
<local folder path>は、C:\NuGetPackagesや~/NuGetPackagesなどのローカル フォルダーへのパスに置き換えます。
dotnet nuget add source <local folder path>
-
SampleRules.dllアセンブリ ファイルを出力ディレクトリからローカル NuGet ソース ディレクトリにコピーします。 既定では、コンパイル済みの.dllファイルのパスはYourSolutionPath\YourProjectPath\bin\DebugまたはYourSolutionPath\YourProjectPath\bin\Releaseです。
手順 5.2: データベース プロジェクトで SampleRules を使用する
- 新しい Microsoft.Build.Sql プロジェクトを作成するか、既存のプロジェクトを開きます。
- プロジェクト ファイル内の SampleRules NuGet パッケージへのパッケージ 参照 を追加します。 次の例は、
.sqlprojファイル内の SampleRules NuGet パッケージへの参照を追加する方法を示しています。
<ItemGroup>
<PackageReference Include="SampleRules" Version="1.0.0" />
</ItemGroup>
手順 5.3: ビルド時にコード分析を有効にする
手順 5.1: SampleRules アセンブリをローカル NuGet ソースに配置する
- NuGet パッケージのローカル ソースがない場合は、ローカル テスト用の NuGet パッケージを格納するフォルダーをローカル コンピューターに追加します。 次のコマンドを実行して、現在の NuGet ソースを確認できます。
dotnet nuget list source
- ローカル ソースが一覧にない場合は、次のコマンドを使用して追加できます。
<local folder path>は、C:\NuGetPackagesや~/NuGetPackagesなどのローカル フォルダーへのパスに置き換えます。
dotnet nuget add source <local folder path>
-
SampleRules.dllアセンブリ ファイルを出力ディレクトリからローカル NuGet ソース ディレクトリにコピーします。 既定では、コンパイル済みの.dllファイルのパスはYourSolutionPath\YourProjectPath\bin\DebugまたはYourSolutionPath\YourProjectPath\bin\Releaseです。
手順 5.2: データベース プロジェクトで SampleRules を使用する
- 新しい Microsoft.Build.Sql プロジェクトを作成するか、既存のプロジェクトを開きます。
- プロジェクト ファイル内の SampleRules NuGet パッケージへのパッケージ 参照 を追加します。 次の例は、
.sqlprojファイル内の SampleRules NuGet パッケージへの参照を追加する方法を示しています。
<ItemGroup>
<PackageReference Include="SampleRules" Version="1.0.0" />
</ItemGroup>