Поделиться через


Создание правил пользовательского анализа кода

Область применения: SQL Server База данных SQL Azure Управляемый экземпляр SQL Azure базе данных SQL в Microsoft Fabric

В этом пошаговом руководстве показаны шаги, используемые для создания правила анализа кода SQL Server. Правило, созданное в этом пошаговом руководстве, используется для предотвращения WAITFOR DELAY инструкций в хранимых процедурах, триггерах и функциях.

В этом пошаговом руководстве вы создадите настраиваемое правило для анализа статического кода Transact-SQL, выполнив следующие действия.

  1. Создайте проект библиотеки классов, включите подпись для этого проекта и добавьте необходимые ссылки.
  2. Создайте два вспомогательных класса C#.
  3. Создайте настраиваемый класс правил C#.
  4. Создайте проект библиотеки классов.
  5. Установите и проверьте новое правило анализа кода.

За исключением инструкций Visual Studio (SQL Server Data Tools), руководство посвящено проектам SQL в стиле ПАКЕТА SDK.

Необходимые компоненты

Для выполнения этого пошагового руководства требуются следующие компоненты:

  • Установленная версия Visual Studio, которая включает sql Server Data Tools и поддерживает разработку платформа .NET Framework C#.
  • Проект SQL Server, содержащий объекты SQL Server.
  • Экземпляр SQL Server, на котором можно развернуть проект базы данных.

Это пошаговое руководство предназначено для пользователей, уже знакомых с функциями SQL Server пакета SQL Server Data Tools. Вы должны ознакомиться с понятиями Visual Studio, такими как создание библиотеки классов, добавление пакетов NuGet и использование редактора кода для добавления кода в класс.

Примечание.

Из-за ограничений пакета SDK в стиле SQL Server Data Tools для нескольких установок Visual Studio необходимо выполнить это пошаговое руководство. Первая установка необходима для создания проекта библиотеки классов, вторая установка необходима для создания проекта базы данных SQL в стиле ПАКЕТА SDK.

Это пошаговое руководство предназначено для пользователей, уже знакомых с функциями SQL Server пакета SQL Server Data Tools. Вы должны ознакомиться с понятиями Visual Studio, такими как создание библиотеки классов, добавление пакетов NuGet и использование редактора кода для добавления кода в класс.

  • Установленная версия Visual Studio Code, которая включает расширение База данных SQL Projects.
  • Проект базы данных SQL, содержащий объекты SQL.
  • Пакет SDK для .NET 8
  • Рекомендуется: расширение комплекта разработки C# для VS Code

Это пошаговое руководство предназначено для пользователей, которые уже знакомы с расширением База данных SQL Projects в Visual Studio Code. Вы должны ознакомиться с концепциями разработки, такими как создание библиотеки классов, добавление пакетов и использование редактора кода для редактирования кода.

  • Текстовый редактор, например редактор файлов в Visual Studio Code.
  • Проект базы данных SQL, содержащий объекты SQL.
  • Пакет SDK для .NET 8

Это пошаговое руководство предназначено для пользователей, которые уже знакомы с проектами SQL. Вы должны ознакомиться с концепциями разработки, такими как создание библиотеки классов, добавление пакетов и использование редактора кода для редактирования кода.

Шаг 1. Создание проекта библиотеки классов

Сначала создайте библиотеку классов. Создание проекта библиотеки классов

  1. Создайте проект библиотеки классов C# (платформа .NET Framework) с именемSampleRules.

  2. Переименуйте файл Class1.cs в AvoidWaitForDelayRule.cs.

  3. В Обозреватель решений щелкните правой кнопкой мыши узел проекта, а затем выберите "Добавить" и "Ссылка".

  4. Выберите System.ComponentModel.Composition вкладку "Сборки\Платформы".

  5. В Обозреватель решений щелкните правой кнопкой мыши узел проекта и выберите пункт "Управление пакетами NuGet". Найдите и установите Microsoft.SqlServer.DacFx пакет NuGet. Выбранная версия должна быть 162.x.x (например 162.2.111, с Visual Studio 2022).

Затем добавьте вспомогательные классы, которые будут использоваться правилом.

Сначала создайте библиотеку классов. Создание проекта библиотеки классов

  1. Создайте проект библиотеки классов C# (платформа .NET Framework) с именемSampleRules.

  2. Переименуйте файл Class1.cs в AvoidWaitForDelayRule.cs.

  3. В Обозреватель решений щелкните правой кнопкой мыши узел проекта, а затем выберите "Добавить" и "Ссылка".

  4. Выберите System.ComponentModel.Composition вкладку "Сборки\Платформы".

  5. В Обозреватель решений щелкните правой кнопкой мыши узел проекта и выберите пункт "Управление пакетами NuGet". Найдите и установите Microsoft.SqlServer.DacFx пакет NuGet. Выбранная версия должна быть 162.x.x (например 162.2.111, с Visual Studio 2022).

Затем добавьте вспомогательные классы, которые будут использоваться правилом.

  1. Запустите Visual Studio Code и откройте папку, в которой вы хотите создать проект.

  2. Откройте окно терминала в Visual Studio Code, выбрав меню "Вид" и "Терминал".

  3. В терминале введите следующие команды, чтобы создать новое решение и проект:

    dotnet new sln
    dotnet new classlib -n SampleRules -o SampleRules
    dotnet sln add SampleRules/SampleRules.csproj
    
  4. Перейдите в SampleRules каталог:

    cd SampleRules
    
  5. Добавьте необходимый пакет NuGet:

    dotnet add package Microsoft.SqlServer.DacFx
    

Затем добавьте вспомогательные классы, которые будут использоваться правилом.

  1. Откройте командную строку или окно терминала и перейдите в папку, в которой вы хотите создать проект.

  2. В терминале введите следующие команды, чтобы создать новое решение и проект:

    dotnet new sln
    dotnet new classlib -n SampleRules -o SampleRules
    dotnet sln add SampleRules/SampleRules.csproj
    
  3. Перейдите в SampleRules каталог:

    cd SampleRules
    
  4. Добавьте необходимый пакет NuGet:

    dotnet add package Microsoft.SqlServer.DacFx
    

Шаг 2. Создание вспомогательных классов настраиваемых правил

Перед созданием класса для самого правила добавьте в проект класс посетителей и класс атрибутов. Эти классы могут быть полезны для создания дополнительных пользовательских правил.

Шаг 2.1. Определение класса WaitForDelayVisitor

Первый класс, который необходимо определить, является классом, производным WaitForDelayVisitor от TSqlConcreteFragmentVisitor. Этот класс предоставляет доступ к WAITFOR DELAY операторам в модели. Классы посетителей используют API-интерфейсы ScriptDom, предоставленные SQL Server. В этом API код Transact-SQL представлен как абстрактное дерево синтаксиса (AST) и классы посетителей могут быть полезны при поиске определенных объектов синтаксиса, таких как WAITFOR DELAY операторы. Эти инструкции могут быть трудно найти с помощью объектной модели, так как они не связаны с определенным свойством или связью объекта, но их можно найти с помощью шаблона посетителя и API ScriptDom .

  1. В обозревателе решений выберите проект SampleRules.

  2. В меню Проект выберите команду Добавить класс. Откроется диалоговое окно Добавление нового элемента. В текстовом поле "Имя" введите WaitForDelayVisitor.cs и нажмите кнопку "Добавить ". Файл WaitForDelayVisitor.cs добавляется в проект в Обозреватель решений.

  1. В обозревателе решений выберите проект SampleRules.

  2. В меню Проект выберите команду Добавить класс. Откроется диалоговое окно Добавление нового элемента. В текстовом поле "Имя" введите WaitForDelayVisitor.cs и нажмите кнопку "Добавить ". Файл WaitForDelayVisitor.cs добавляется в проект в Обозреватель решений.

  1. Откройте представление обозревателя в Visual Studio Code.

  2. Создайте файл с именем WaitForDelayVisitor.cs в папке SampleRules .

  1. Перейдите к каталогу SampleRules.
  2. Создайте файл с именем WaitForDelayVisitor.cs.
  1. Откройте файл и обновите содержимое WaitForDelayVisitor.cs , чтобы соответствовать следующему коду:

    using System.Collections.Generic;
    using Microsoft.SqlServer.TransactSql.ScriptDom;
    namespace SampleRules {
        class WaitForDelayVisitor {}
    }
    
  2. В объявлении класса измените модификатор доступа на внутренний и наследуйте класс из TSqlConcreteFragmentVisitor:

    internal class WaitForDelayVisitor : TSqlConcreteFragmentVisitor {}
    
  3. Добавьте следующий код для определения переменной элемента списка.

    public IList<WaitForStatement> WaitForDelayStatements { get; private set; }
    
  4. Задайте конструктор класса, добавив следующий код:

    public WaitForDelayVisitor() {
       WaitForDelayStatements = new List<WaitForStatement>();
    }
    
  5. Переопределите 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.

  6. В меню File (Файл) выберите пункт Save (Сохранить).

Шаг 2.2. Добавление файла ресурса и трех строк ресурсов

Затем добавьте файл ресурсов, определяющий имя правила, описание правила и категорию, в которой правило будет отображаться в интерфейсе конфигурации правила.

  1. В обозревателе решений выберите проект SampleRules. В меню "Проект" выберите "Добавить" и "Создать элемент". Откроется диалоговое окно Добавление нового элемента.

  2. В списке установленных шаблонов выберите "Общие". В области сведений выберите файл ресурсов.

  3. В поле Имявведите RuleResources.resx. Откроется редактор ресурсов без каких-либо заданных ресурсов.

  4. Задайте четыре строки ресурса следующим образом:

    Имя. Значение
    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}.
  5. В меню "Файл" выберите "Сохранить правилоResources.resx".

  1. В обозревателе решений выберите проект SampleRules. В меню "Проект" выберите "Добавить" и "Создать элемент". Откроется диалоговое окно Добавление нового элемента.

  2. В списке установленных шаблонов выберите "Общие". В области сведений выберите файл ресурсов.

  3. В поле Имявведите RuleResources.resx. Откроется редактор ресурсов без каких-либо заданных ресурсов.

  4. Задайте четыре строки ресурса следующим образом:

    Имя. Значение
    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}.
  5. В меню "Файл" выберите "Сохранить правилоResources.resx".

  1. В каталоге SampleRules создайте файл с именем RuleResources.resx.

  2. Откройте файл 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>
    
  3. Сохраните файл RuleResources.resx.

  4. 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>
    
  5. Сохраните файл SampleRules.csproj.

  1. В каталоге SampleRules создайте файл с именем RuleResources.resx.

  2. Откройте файл 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>
    
  3. Сохраните файл RuleResources.resx.

  4. 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>
    
  5. Сохраните файл SampleRules.csproj.

Шаг 2.3. Определение класса LocalizedExportCodeAnalysisRuleAttribute

Второй класс .LocalizedExportCodeAnalysisRuleAttribute.cs Это расширение встроенной Microsoft.SqlServer.Dac.CodeAnalysis.ExportCodeAnalysisRuleAttribute платформы, которая поддерживает чтение DisplayName и Description использование правилом из файла ресурсов. Этот класс особенно полезен, если вы планируете использование ваших правил на нескольких языках.

  1. В обозревателе решений выберите проект SampleRules.

  2. В меню Проект выберите команду Добавить класс. Откроется диалоговое окно Добавление нового элемента. В текстовом поле "Имя" введите LocalizedExportCodeAnalysisRuleAttribute.cs и нажмите кнопку "Добавить ". Файл будет добавлен в проект в Обозревателе решений.

  1. В обозревателе решений выберите проект SampleRules.

  2. В меню Проект выберите команду Добавить класс. Откроется диалоговое окно Добавление нового элемента. В текстовом поле "Имя" введите LocalizedExportCodeAnalysisRuleAttribute.cs и нажмите кнопку "Добавить ". Файл будет добавлен в проект в Обозревателе решений.

  1. Перейдите к каталогу в представлении SampleRules обозревателя в Visual Studio Code.
  2. Создайте файл с именем LocalizedExportCodeAnalysisRuleAttribute.cs.
  1. Перейдите к каталогу SampleRules.
  2. Создайте файл с именем LocalizedExportCodeAnalysisRuleAttribute.cs.
  1. Откройте файл и обновите его содержимое, чтобы оно соответствовало следующему коду.

    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 для отображения сведений о правиле в пользовательском интерфейсе.

  1. В обозревателе решений выберите проект SampleRules.

  2. В меню "Проект" выберите "Добавить" и "Класс". Откроется диалоговое окно Добавление нового элемента. В текстовом поле "Имя" введите SampleRuleConstants.cs и нажмите кнопку "Добавить ". Файл SampleRuleConstants.cs добавляется в проект в Обозреватель решений.

  1. В обозревателе решений выберите проект SampleRules.

  2. В меню "Проект" выберите "Добавить" и "Класс". Откроется диалоговое окно Добавление нового элемента. В текстовом поле "Имя" введите SampleRuleConstants.cs и нажмите кнопку "Добавить ". Файл SampleRuleConstants.cs добавляется в проект в Обозреватель решений.

  1. Перейдите к каталогу в представлении SampleRules обозревателя в Visual Studio Code.
  2. Создайте файл с именем SampleRuleConstants.cs.
  1. Перейдите к каталогу SampleRules.
  2. Создайте файл с именем SampleRuleConstants.cs.
  1. 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";
        }
    }
    
  2. В меню File (Файл) выберите пункт Save (Сохранить).

Шаг 3. Создание пользовательского класса правил

После добавления вспомогательных классов, которые будет использовать пользовательское правило анализа кода, создайте пользовательский класс правил и назовите его AvoidWaitForDelayRule. Пользовательское AvoidWaitForDelayRule правило будет использоваться для того, чтобы разработчики баз данных избегали WAITFOR DELAY инструкций в хранимых процедурах, триггерах и функциях.

Шаг 3.1. Создание класса AvoidWaitForDelayRule

  1. В обозревателе решений выберите проект SampleRules.

  2. В меню "Проект" выберите "Добавить" и "Класс". Откроется диалоговое окно Добавление нового элемента. В текстовом поле "Имя" введите AvoidWaitForDelayRule.cs и нажмите кнопку "Добавить". Файл AvoidWaitForDelayRule.cs добавляется в проект в Обозреватель решений.

  1. В обозревателе решений выберите проект SampleRules.

  2. В меню "Проект" выберите "Добавить" и "Класс". Откроется диалоговое окно Добавление нового элемента. В текстовом поле "Имя" введите AvoidWaitForDelayRule.cs и нажмите кнопку "Добавить". Файл AvoidWaitForDelayRule.cs добавляется в проект в Обозреватель решений.

  1. Перейдите к каталогу в представлении SampleRules обозревателя в Visual Studio Code.
  2. Создайте файл с именем AvoidWaitForDelayRule.cs.
  1. Перейдите к каталогу SampleRules.
  2. Создайте файл с именем AvoidWaitForDelayRule.cs.
  1. 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 {}
    }
    
  2. В объявлении класса измените 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
    
  3. Производный AvoidWaitForDelayRule Microsoft.SqlServer.Dac.CodeAnalysis.SqlCodeAnalysisRule класс от базового класса:

    public sealed class AvoidWaitForDelayRule : SqlCodeAnalysisRule
    
  4. Добавьте LocalizedExportCodeAnalysisRuleAttribute в свой класс.

    LocalizedExportCodeAnalysisRuleAttribute позволяет службе анализа кода обнаруживать пользовательские правила анализа кода. В анализе кода можно использовать только классы, ExportCodeAnalysisRuleAttribute помеченные (или атрибутом, наследуемым от этого).

    LocalizedExportCodeAnalysisRuleAttribute предоставляет некоторые необходимые метаданные, используемые службой. Сюда входит уникальный идентификатор этого правила, отображаемое имя, отображаемое в пользовательском интерфейсе 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 можно использовать вместо этого.

  5. Добавьте конструктор, который настраивает 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
       };
    }
    
  6. Добавьте переопределение для 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);
    }
    
  7. В меню Файл выберите команду Сохранить.

Шаг 4. Создание библиотеки классов

  1. В меню "Проект" выберите "Свойства SampleRules".
  2. Перейдите на вкладку "Подписывание ".
  3. Выберите " Подписать сборку".
  4. В разделе "Выбор файла ключа строгого имени" нажмите кнопку <"Создать>".
  5. В диалоговом окне "Создание ключа строгого имени" введите имяMyRefKey файла ключа.
  6. (Необязательно) Можно указать пароль для файла ключа для строгого имени.
  7. Нажмите ОК.
  8. В меню File (Файл) выберите команду Save All (Сохранить все).
  9. В меню Сборка выберите команду Собрать решение.
  1. В меню "Проект" выберите "Свойства SampleRules".
  2. Перейдите на вкладку "Подписывание ".
  3. Выберите " Подписать сборку".
  4. В разделе "Выбор файла ключа строгого имени" нажмите кнопку <"Создать>".
  5. В диалоговом окне "Создание ключа строгого имени" введите имяMyRefKey файла ключа.
  6. (Необязательно) Можно указать пароль для файла ключа для строгого имени.
  7. Нажмите ОК.
  8. В меню File (Файл) выберите команду Save All (Сохранить все).
  9. В меню Сборка выберите команду Собрать решение.
  1. Откройте окно терминала в Visual Studio Code, выбрав меню "Вид" и "Терминал".

  2. В терминале введите следующую команду, чтобы создать проект:

    dotnet build /p:Configuration=Release
    
  1. Перейдите к каталогу SampleRules.

  2. Выполните следующую команду, чтобы создать проект:

    dotnet build /p:Configuration=Release
    

Шаг 5. Установка и проверка нового правила анализа кода

Затем необходимо установить сборку, чтобы она загружала при сборке проекта базы данных SQL.

Чтобы установить правило, которое будет выполняться при сборке исходного проекта SQL с помощью Visual Studio, необходимо скопировать сборку и связанный .pdb файл в папку Extensions.

Шаг 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используется. Professional Community Замените Enterprise или в зависимости от установленного выпуска Visual Studio.

Скопируйте файл сборки SampleRules.dll из выходного каталога в <Visual Studio Install Dir>\Common7\IDE\Extensions\Microsoft\SQLDB\DAC\Extensions каталог. По умолчанию путь к скомпилированному .dll файлу имеет YourSolutionPath\YourProjectPath\bin\Debug или YourSolutionPath\YourProjectPath\bin\Release.

Примечание.

Возможно, потребуется создать Extensions каталог.

Теперь правило должно быть установлено и появится после перезапуска Visual Studio. Затем запустите новый сеанс Visual Studio и создайте проект базы данных.

Шаг 5.2. Запуск нового сеанса Visual Studio и создание проекта базы данных

  1. Запустите второй сеанс работы Visual Studio.
  2. Выберите File>New>Project ( Файл > Создать > Проект).
  3. В диалоговом окне "Новый проект" найдите и выберите проект базы данных SQL Server.
  4. В текстовом поле "Имя" введите SampleRulesDB и нажмите кнопку "ОК".

Шаг 5.3. Включение правила анализа кода AvoidWaitForRule

  1. В обозревателе решений выберите проект SampleRulesDB.
  2. В меню Проект выберите пункт Свойства. SampleRulesDB Отображается страница свойств.
  3. Выберите анализ кода. Вы увидите новую категорию с именем RuleSamples.CategorySamples.
  4. Разверните раздел RuleSamples.CategorySamples. Вы должны увидеть SR1004: Avoid WAITFOR DELAY statement in stored procedures, triggers, and functions.
  5. Включите это правило, установив флажок рядом с именем правила и флажком включить анализ кода в сборке. Дополнительные сведения о включении анализа кода см. в обзоре анализа кода.
  6. При использовании действия сборки проекта правило будет выполнено, и все WAITFOR DELAY найденные инструкции будут сообщаться как предупреждения.

Чтобы установить правило, которое будет выполняться при сборке исходного проекта SQL с помощью Visual Studio, необходимо скопировать сборку и связанный .pdb файл в папку Extensions.

Шаг 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используется. Professional Community Замените Enterprise или в зависимости от установленного выпуска Visual Studio.

Скопируйте файл сборки SampleRules.dll из выходного каталога в <Visual Studio Install Dir>\Common7\IDE\Extensions\Microsoft\SQLDB\DAC\Extensions каталог. По умолчанию путь к скомпилированному .dll файлу имеет YourSolutionPath\YourProjectPath\bin\Debug или YourSolutionPath\YourProjectPath\bin\Release.

Примечание.

Возможно, потребуется создать Extensions каталог.

Теперь правило должно быть установлено и появится после перезапуска Visual Studio. Затем запустите новый сеанс Visual Studio и создайте проект базы данных.

Шаг 5.2. Запуск нового сеанса Visual Studio и создание проекта базы данных

  1. Запустите второй сеанс работы Visual Studio.
  2. Выберите File>New>Project ( Файл > Создать > Проект).
  3. В диалоговом окне "Новый проект" найдите и выберите проект базы данных SQL Server, стиль SDK (предварительная версия).
  4. В текстовом поле "Имя" введите SampleRulesDB и нажмите кнопку "ОК".

Шаг 5.3. Включение правила анализа кода AvoidWaitForRule

  1. В обозревателе решений выберите проект SampleRulesDB.
  2. Дважды щелкните узел проекта, чтобы открыть файл проекта. Файл SampleRulesDB проекта отображается в текстовом редакторе.
  3. Включите анализ кода для сборки в файле проекта SQL, задав RunSqlCodeAnalysis для свойства значение true.
  4. При использовании действия сборки проекта правило будет выполнено, и все WAITFOR DELAY найденные инструкции будут сообщаться как предупреждения.

Решение доступно для проектов в стиле SDK для установки пользовательских правил до тех пор, пока не будут поддерживаться ссылки на пакеты.

  1. Запустите dotnet restore для восстановления зависимостей проекта в проекте SQL, гарантируя, что локальный кэш пакетов NuGet содержит Microsoft.Build.Sql.
  2. Обратите внимание на версию Microsoft.Build.Sql, используемую в файле проекта SQL, например 0.1.19-preview.
  3. Скопируйте файл сборки SampleRules.dll из выходного каталога в ~/.nuget/packages/microsoft.build.sql/0.1.19-preview/tools/netstandard2.1 каталог. Точный путь к каталогу может отличаться в зависимости от версии Microsoft.Build.Sql, используемой в файле проекта SQL.
  4. Включите анализ кода для сборки в файле проекта SQL, задав RunSqlCodeAnalysis для свойства значение true.
  5. Выполните dotnet build сборку проекта SQL и выполните настраиваемое правило.

Решение доступно для проектов в стиле SDK для установки пользовательских правил до тех пор, пока не будут поддерживаться ссылки на пакеты.

  1. Запустите dotnet restore для восстановления зависимостей проекта в проекте SQL, гарантируя, что локальный кэш пакетов NuGet содержит Microsoft.Build.Sql.
  2. Обратите внимание на версию Microsoft.Build.Sql, используемую в файле проекта SQL, например 0.1.19-preview.
  3. Скопируйте файл сборки SampleRules.dll из выходного каталога в ~/.nuget/packages/microsoft.build.sql/0.1.19-preview/tools/netstandard2.1 каталог. Точный путь к каталогу может отличаться в зависимости от версии Microsoft.Build.Sql, используемой в файле проекта SQL.
  4. Включите анализ кода для сборки в файле проекта SQL, задав RunSqlCodeAnalysis для свойства значение true.
  5. Выполните dotnet build сборку проекта SQL и выполните настраиваемое правило.