사용자 지정 코드 분석 규칙 작성
적용 대상: Microsoft Fabric의 SQL Server
Azure SQL Database
Azure SQL Managed Instance
SQL 데이터베이스
이 연습에서는 SQL Server 코드 분석 규칙을 만드는 데 사용되는 단계를 보여 줍니다. 이 연습에서 만든 규칙은 저장 프로시저, 트리거, 및 함수에서 WAITFOR DELAY
문을 방지하는 데 사용됩니다.
이 연습에서는 다음 단계를 사용하여 Transact-SQL 정적 코드 분석에 대한 사용자 지정 규칙을 만듭니다.
- 클래스 라이브러리 프로젝트를 만들고, 해당 프로젝트에 대한 서명을 사용하도록 설정하고, 필요한 참조를 추가합니다.
- 두 도우미 C# 클래스를 만듭니다.
- C# 사용자 지정 규칙 클래스를 만듭니다.
- 클래스 라이브러리 프로젝트를 빌드합니다.
- 새 코드 분석 규칙을 설치하고 테스트합니다.
이 가이드에서는 Visual Studio(SQL Server Data Tools) 지침을 제외하고 SDK 스타일 SQL 프로젝트에 중점을 둡니다.
필수 조건
이 연습을 완료하려면 다음과 같은 구성 요소가 필요합니다.
- SQL Server Data Tools가 포함되고 C# .NET Framework 개발이 포함된 Visual Studio 설치 관리자 버전.
- SQL Server 개체가 포함된 SQL Server 프로젝트.
- 데이터베이스 프로젝트를 배포할 수 있는 SQL Server의 인스턴스가 필요합니다.
이 연습은 SQL Server Data Tools의 SQL Server 기능에 이미 익숙한 사용자를 위한 것입니다. 또한 클래스 라이브러리를 만드는 방법, NuGet 패키지 추가 및 코드 편집기를 사용하여 클래스에 코드를 추가하는 방법과 같은 Visual Studio 개념을 잘 알고 있어야 합니다.
참고 항목
SDK 스타일 SQL Server Data Tools의 미리 보기 제한 사항으로 인해 이 연습을 완료하려면 여러 Visual Studio 설치가 필요합니다. 첫 번째 설치는 클래스 라이브러리 프로젝트를 만드는 데 필요하며, 두 번째 설치는 SDK 스타일 SQL 데이터베이스 프로젝트를 만드는 데 필요합니다.
- .NET 8.0 SDK
- Visual Studio 2022 Community, Professional 또는 Enterprise.
- Visual Studio 2022에 설치된 SQL Server Data Tools, SDK 스타일(미리 보기)
- C# .NET Framework 개발을 지원하는 Visual Studio 버전이 설치되어 있습니다.
- SQL Server 개체가 포함된 SQL Server 프로젝트.
이 연습은 SQL Server Data Tools의 SQL Server 기능에 이미 익숙한 사용자를 위한 것입니다. 또한 클래스 라이브러리를 만드는 방법, NuGet 패키지 추가 및 코드 편집기를 사용하여 클래스에 코드를 추가하는 방법과 같은 Visual Studio 개념을 잘 알고 있어야 합니다.
- SQL Database 프로젝트 확장을 포함하는 설치된 Visual Studio Code 버전입니다.
- SQL 데이터베이스 개체가 포함된 SQL 프로젝트.
- .NET 8.0 SDK
- 권장: VS Code용 C# Dev Kit 확장
이 연습은 Visual Studio Code의 SQL Database 프로젝트 확장에 이미 익숙한 사용자를 위한 것입니다. 클래스 라이브러리를 만들고, 패키지를 추가하고, 코드 편집기를 사용하여 코드를 편집하는 방법과 같은 개발 개념을 잘 알고 있어야 합니다.
- Visual Studio Code 내 파일 편집기와 같은 텍스트 편집기.
- SQL 데이터베이스 개체가 포함된 SQL 프로젝트.
- .NET 8.0 SDK
이 연습은 SQL 프로젝트에 이미 익숙한 사용자를 위한 것입니다. 클래스 라이브러리를 만들고, 패키지를 추가하고, 코드 편집기를 사용하여 코드를 편집하는 방법과 같은 개발 개념을 잘 알고 있어야 합니다.
1단계: 클래스 라이브러리 프로젝트를 만듭니다.
클래스 라이브러리를 먼저 만드세요. 클래스 라이브러리 프로젝트를 만들려면
SampleRules
(이)라는 이름의 C# 클래스 라이브러리(.NET Framework) 프로젝트를 만듭니다.파일의 이름을
Class1.cs
에서AvoidWaitForDelayRule.cs
로 바꿉니다.솔루션 탐색기에서 프로젝트 노드를 마우스 오른쪽 단추로 클릭한 다음 추가 및 참조를 선택합니다.
Assemblies\Frameworks 탭에서
System.ComponentModel.Composition
을(를) 선택합니다.솔루션 탐색기에서 프로젝트 노드를 마우스 오른쪽 단추로 클릭한 다음, NuGet 패키지 관리를 선택합니다.
Microsoft.SqlServer.DacFx
NuGet 패키지를 찾아 설치 합니다. 선택한 버전은 Visual Studio 2022와162.x.x
(예:162.2.111
)이어야 합니다.
다음으로 규칙에서 사용할 지원 클래스를 추가합니다.
클래스 라이브러리를 먼저 만드세요. 클래스 라이브러리 프로젝트를 만들려면
SampleRules
(이)라는 이름의 C# 클래스 라이브러리(.NET Framework) 프로젝트를 만듭니다.파일의 이름을
Class1.cs
에서AvoidWaitForDelayRule.cs
로 바꿉니다.솔루션 탐색기에서 프로젝트 노드를 마우스 오른쪽 단추로 클릭한 다음 추가 및 참조를 선택합니다.
Assemblies\Frameworks 탭에서
System.ComponentModel.Composition
을(를) 선택합니다.솔루션 탐색기에서 프로젝트 노드를 마우스 오른쪽 단추로 클릭한 다음, NuGet 패키지 관리를 선택합니다.
Microsoft.SqlServer.DacFx
NuGet 패키지를 찾아 설치 합니다. 선택한 버전은 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.csproj
SampleRules
디렉터리로 변경합니다.cd SampleRules
필요한 NuGet 패키지 추가
dotnet add package Microsoft.SqlServer.DacFx
다음으로 규칙에서 사용할 지원 클래스를 추가합니다.
명령 프롬프트 또는 터미널 창을 열고 프로젝트를 만들 폴더로 탐색합니다.
터미널에서 다음 명령을 입력하여 새 솔루션 및 프로젝트를 만듭니다.
dotnet new sln dotnet new classlib -n SampleRules -o SampleRules dotnet sln add SampleRules/SampleRules.csproj
SampleRules
디렉터리로 변경합니다.cd SampleRules
필요한 NuGet 패키지 추가
dotnet add package Microsoft.SqlServer.DacFx
2단계: 사용자 지정 규칙 도우미 클래스 만들기
규칙 자체의 클래스를 만들기 전에 방문자 클래스와 특성 클래스를 프로젝트에 추가합니다. 이러한 클래스는 추가 사용자 지정 규칙을 만드는 데 유용할 수 있습니다.
2.1단계: WaitForDelayVisitor 클래스 정의
정의해야 하는 첫 번째 클래스는 TSqlConcreteFragmentVisitor에서 파생된 WaitForDelayVisitor
클래스입니다. 이 클래스는 모델의 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 {} }
클래스 선언에서 액세스 한정자를 내부로 변경하고
TSqlConcreteFragmentVisitor
에서 클래스를 파생합니다.internal class WaitForDelayVisitor : TSqlConcreteFragmentVisitor {}
다음 코드를 추가하여 멤버 변수 나열을 정의합니다.
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단계: 리소스 파일 및 세 개의 리소스 문자열 추가
다음으로 규칙 이름, 규칙 설명 및 규칙이 규칙 구성 인터페이스에 표시되는 범주를 정의하는 리소스 파일을 추가합니다.
솔루션 탐색기에서
SampleRules
프로젝트를 선택합니다. 프로젝트 메뉴에서 추가 및 새 항목을 선택합니다. 새 항목 추가 대화 상자가 나타납니다.설치된 템플릿 목록에서 일반을 클릭합니다. 세부 정보 창에서 리소스 파일을 클릭합니다.
이름에
RuleResources.resx
을(를) 입력합니다. 리소스 편집기가 정의되지 않은 상태에서 나타납니다.다음과 같이 네 개의 리소스 문자열을 정의합니다.
속성 값 AvoidWaitForDelay_ProblemDescription
WAITFOR DELAY statement was found in {0}.
AvoidWaitForDelay_RuleName
Avoid using WaitFor Delay statements in stored procedures, functions and triggers.
CategorySamples
SamplesCategory
CannotCreateResourceManager
Can't create ResourceManager for {0} from {1}.
파일 메뉴에서 RuleResources.resx 저장을 선택합니다.
솔루션 탐색기에서
SampleRules
프로젝트를 선택합니다. 프로젝트 메뉴에서 추가 및 새 항목을 선택합니다. 새 항목 추가 대화 상자가 나타납니다.설치된 템플릿 목록에서 일반을 클릭합니다. 세부 정보 창에서 리소스 파일을 클릭합니다.
이름에
RuleResources.resx
을(를) 입력합니다. 리소스 편집기가 정의되지 않은 상태에서 나타납니다.다음과 같이 네 개의 리소스 문자열을 정의합니다.
속성 값 AvoidWaitForDelay_ProblemDescription
WAITFOR DELAY statement was found in {0}.
AvoidWaitForDelay_RuleName
Avoid using WaitFor Delay statements in stored procedures, functions and triggers.
CategorySamples
SamplesCategory
CannotCreateResourceManager
Can'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 클래스 정의
두 번째 클래스는 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단계: 사용자 지정 규칙 클래스 만들기
사용자 지정 Code Analysis 규칙에서 사용할 도우미 클래스를 추가한 다음 사용자 지정 규칙 클래스를 만들고 이름을 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
클래스 선언에서 액세스 한정자를 공개로 변경합니다./// <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 AvoidWaitForDelayRule
AvoidWaitForDelayRule
기본 클래스에서Microsoft.SqlServer.Dac.CodeAnalysis.SqlCodeAnalysisRule
클래스를 파생시킵니다.public sealed class AvoidWaitForDelayRule : SqlCodeAnalysisRule
클래스에
LocalizedExportCodeAnalysisRuleAttribute
를 추가합니다.LocalizedExportCodeAnalysisRuleAttribute
을(를) 사용하면 Code Analysis 서비스에서 Code Analysis 코드 분석 규칙을 검색할 수 있습니다.ExportCodeAnalysisRuleAttribute
(또는 이 특성에서 상속되는 특성)로 표시된 클래스만 Code Analysis에 사용할 수 있습니다.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
에 해당해야 합니다. 모델의 일치하는 각 요소에 대해 규칙이 한 번 호출됩니다. 전체 모델을 분석하려는 경우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.SqlRuleExecutionContext
을(를) 입력 매개 변수로 사용하는Microsoft.SqlServer.Dac.CodeAnalysis.SqlAnalysisRule.Analyze
(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
를 입력합니다. - (선택 사항)강력한 이름 키 파일의 암호를 지정할 수 있습니다.
- 확인을 선택합니다.
- 파일 메뉴에서 모두 저장을 선택합니다.
- 빌드 메뉴에서 솔루션 빌드를 선택합니다.
- 프로젝트 메뉴에서 SampleRules 속성을 클릭합니다.
- 서명 탭 선택
- 어셈블리 서명을 클릭합니다.
- 강력한 이름 키 파일 선택에서 <새로 만들기>를 클릭합니다.
- 강력한 이름 키 만들기 대화 상자에서 키 파일 이름에
MyRefKey
를 입력합니다. - (선택 사항)강력한 이름 키 파일의 암호를 지정할 수 있습니다.
- 확인을 선택합니다.
- 파일 메뉴에서 모두 저장을 선택합니다.
- 빌드 메뉴에서 솔루션 빌드를 선택합니다.
Visual Studio Code에서 보기 메뉴를 선택한 다음 터미널을 선택하여 터미널 창을 엽니다.
터미널에서 다음 명령을 입력하여 프로젝트를 빌드합니다.
dotnet build /p:Configuration=Release
SampleRules
디렉터리로 이동합니다.다음 명령을 실행하여 프로젝트를 빌드합니다.
dotnet build /p:Configuration=Release
5단계: 새 코드 분석 규칙 설치 및 테스트
그런 다음 SQL 데이터베이스 프로젝트를 구축할 때 어셈블리가 로드되도록 설치해야 합니다.
Visual Studio를 사용하여 원래 SQL 프로젝트를 빌드할 때 실행되는 규칙을 설치하려면 어셈블리 및 연결된 .pdb
파일을 Extensions 폴더에 복사해야 합니다.
5.1단계: SampleRules 어셈블리 설치
다음으로 어셈블리 정보를 확장 디렉터리에 복사합니다. 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
으로 변경합니다.
출력 디렉터리에서 <Visual Studio Install Dir>\Common7\IDE\Extensions\Microsoft\SQLDB\DAC\Extensions
디렉터리로 SampleRules.dll 어셈블리 파일을 복사합니다. 기본적으로 컴파일된 .dll
파일의 경로는 YourSolutionPath\YourProjectPath\bin\Debug
또는 YourSolutionPath\YourProjectPath\bin\Release
입니다.
참고 항목
Extensions
디렉터리를 만들어야 할 수도 있습니다.
규칙이 설치되었으며 Visual Studio를 다시 시작하면 나타납니다. 다음으로 새 Visual Studio 세션을 시작하고 데이터베이스 프로젝트를 만듭니다.
5.2단계: 새 Visual Studio 세션 시작 및 데이터베이스 프로젝트 만들기
- Visual Studio의 두 번째 세션을 시작합니다.
- 파일>새>프로젝트를 선택합니다.
- 새 프로젝트 대화 상자에서 SQL Server 데이터베이스 프로젝트를 찾아 선택합니다.
- 이름 상자에
SampleRulesDB
을(를) 입력하고 확인을 선택합니다.
5.3단계: AvoidWaitForRule 코드 분석 규칙 사용
- 솔루션 탐색기에서
SampleRulesDB
프로젝트를 선택합니다. - 프로젝트 메뉴에서 속성을 선택합니다.
SampleRulesDB
속성 페이지가 표시됩니다. - Code Analysis를 선택합니다.
RuleSamples.CategorySamples
라는 새 범주가 표시됩니다. RuleSamples.CategorySamples
를 확장합니다.SR1004: Avoid WAITFOR DELAY statement in stored procedures, triggers, and functions
과 같은 결과가 표시됩니다.- 규칙 이름 옆의 확인란과 빌드 시 코드 분석 사용 확인란을 선택하여 이 규칙을 사용하도록 설정합니다. 코드 분석을 사용하도록 설정하는 방법에 대한 자세한 내용은 코드 분석 개요를 확인하세요.
- 프로젝트 빌드 작업을 사용하면 규칙이 실행되고 발견된 모든
WAITFOR DELAY
문이 경고로 보고됩니다.
Visual Studio를 사용하여 원래 SQL 프로젝트를 빌드할 때 실행되는 규칙을 설치하려면 어셈블리 및 연결된 .pdb
파일을 Extensions 폴더에 복사해야 합니다.
5.1단계: SampleRules 어셈블리 설치
다음으로 어셈블리 정보를 확장 디렉터리에 복사합니다. 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
으로 변경합니다.
출력 디렉터리에서 <Visual Studio Install Dir>\Common7\IDE\Extensions\Microsoft\SQLDB\DAC\Extensions
디렉터리로 SampleRules.dll 어셈블리 파일을 복사합니다. 기본적으로 컴파일된 .dll
파일의 경로는 YourSolutionPath\YourProjectPath\bin\Debug
또는 YourSolutionPath\YourProjectPath\bin\Release
입니다.
참고 항목
Extensions
디렉터리를 만들어야 할 수도 있습니다.
규칙이 설치되었으며 Visual Studio를 다시 시작하면 나타납니다. 다음으로 새 Visual Studio 세션을 시작하고 데이터베이스 프로젝트를 만듭니다.
5.2단계: 새 Visual Studio 세션 시작 및 데이터베이스 프로젝트 만들기
- Visual Studio의 두 번째 세션을 시작합니다.
- 파일>새>프로젝트를 선택합니다.
- 새 프로젝트 대화 상자에서 SQL Server 데이터베이스 프로젝트, SDK 스타일(미리 보기)을 찾아 선택합니다.
- 이름 상자에
SampleRulesDB
을(를) 입력하고 확인을 선택합니다.
5.3단계: AvoidWaitForRule 코드 분석 규칙 사용
- 솔루션 탐색기에서
SampleRulesDB
프로젝트를 선택합니다. - 프로젝트 노드를 두 번 클릭하여 프로젝트 파일을 엽니다.
SampleRulesDB
프로젝트 파일이 텍스트 편집기에서 표시됩니다. RunSqlCodeAnalysis
속성을true
(으)로 설정하여 SQL 프로젝트 파일에서 빌드 시 코드 분석을 사용하도록 설정합니다.- 프로젝트 빌드 작업을 사용하면 규칙이 실행되고 발견된 모든
WAITFOR DELAY
문이 경고로 보고됩니다.
패키지 참조가 지원될 때까지 SDK 스타일 프로젝트에서 사용자 지정 규칙을 설치하는 해결 방법을 사용할 수 있습니다.
dotnet restore
을(를) 실행하여 SQL 프로젝트에 대한 프로젝트 종속성을 복원하고 로컬 NuGet 패키지 캐시에 Microsoft.Build.Sql이 포함되어 있는지 확인합니다.0.1.19-preview
와(과) 같은, SQL 프로젝트 파일에서 사용되는 Microsoft.Build.Sql 버전을 확인합니다.- 출력 디렉터리에서
SampleRules.dll
디렉터리로~/.nuget/packages/microsoft.build.sql/0.1.19-preview/tools/netstandard2.1
어셈블리 파일을 복사합니다. 정확한 디렉터리 경로는 SQL 프로젝트 파일에 사용되는 Microsoft.Build.Sql 버전에 따라 달라질 수 있습니다. RunSqlCodeAnalysis
속성을true
(으)로 설정하여 SQL 프로젝트 파일에서 빌드 시 코드 분석을 사용하도록 설정합니다.dotnet build
을(를) 실행하여 SQL 프로젝트를 빌드하고 사용자 지정 규칙을 실행합니다.
패키지 참조가 지원될 때까지 SDK 스타일 프로젝트에서 사용자 지정 규칙을 설치하는 해결 방법을 사용할 수 있습니다.
dotnet restore
을(를) 실행하여 SQL 프로젝트에 대한 프로젝트 종속성을 복원하고 로컬 NuGet 패키지 캐시에 Microsoft.Build.Sql이 포함되어 있는지 확인합니다.0.1.19-preview
와(과) 같은, SQL 프로젝트 파일에서 사용되는 Microsoft.Build.Sql 버전을 확인합니다.- 출력 디렉터리에서
SampleRules.dll
디렉터리로~/.nuget/packages/microsoft.build.sql/0.1.19-preview/tools/netstandard2.1
어셈블리 파일을 복사합니다. 정확한 디렉터리 경로는 SQL 프로젝트 파일에 사용되는 Microsoft.Build.Sql 버전에 따라 달라질 수 있습니다. RunSqlCodeAnalysis
속성을true
(으)로 설정하여 SQL 프로젝트 파일에서 빌드 시 코드 분석을 사용하도록 설정합니다.dotnet build
을(를) 실행하여 SQL 프로젝트를 빌드하고 사용자 지정 규칙을 실행합니다.