演练:创作 SQL 的自定义静态代码分析规则程序集

此分步主题演示了用于创建 SQL 代码分析规则的各个步骤。 此演练中创建的规则用于避免在存储过程、触发器和函数中出现 WAITFOR DELAY 语句。

在此演练中,将使用以下过程创建 Transact-SQL 静态代码分析的自定义规则:

  1. 创建类库、对项目启用签名和添加必要的引用。

  2. 创建两个帮助器 C# 类。

  3. 创建 C# 自定义规则类。

  4. 创建用于注册程序集的 XML 文件。

  5. 将创建所得的 DLL 和 XML 文件复制到 Extensions 目录中以将其注册。

  6. 确认新的代码分析规则已就绪。

系统必备

必须安装 Visual Studio 高级专业版 或 Visual Studio 旗舰版 才能完成此演练。

创建 SQL 的自定义代码分析规则

首先,将创建一个类库。

创建类库

  1. 在**“文件”菜单上,单击“新建”,然后单击“项目”**。

  2. 在**“添加新项目”对话框的“已安装的模板”列表中,单击“Visual C#”**。

  3. 在细节窗格中,选择**“类库”**。

  4. 在**“名称”文本框中,键入 SampleRules,然后单击“确定”**。

接下来,将为项目签名。

对项目启用签名

  1. 在**“解决方案资源管理器”选中 SampleRules 项目节点的情况下,从“项目”菜单中,单击“属性”(或在“解决方案资源管理器”中右击该项目节点,然后单击“属性”**)。

  2. 单击**“签名”**选项卡。

  3. 选中**“为程序集签名”**复选框。

  4. 指定一个新密钥文件。 在**“选择强名称密钥文件”下拉列表中,选择“<新建...>”**。

    将显示**“创建强名称密钥”**对话框。 有关更多信息,请参见“创建强名称密钥”对话框

  5. 在**“创建强名称密钥”对话框的“名称”**文本框中,键入 SampleRulesKey 作为新密钥文件的名称。 在此演练中无须提供密码。 有关更多信息,请参见管理程序集签名和清单签名

接下来,要向项目添加必要的引用。

向项目添加适当的引用

  1. 在**“解决方案资源管理器”**中,选择 SampleRules 项目。

  2. 在**“项目”菜单上,单击“添加引用”**。

    将打开**“添加引用”**对话框。 有关更多信息,请参见如何:在 Visual Studio 中添加或移除引用

  3. 选择**“.NET”**选项卡。

  4. 在**“组件名称”**列中,找到以下组件:

    提示

    若要选择多个组件,请在按住 Ctrl 键的同时单击各个组件。

  5. 选择了所有所需的组件后,单击**“确定”**。

    此时将在**“解决方案资源管理器”中该项目的“引用”**节点下显示所选的引用。

创建自定义代码分析规则支持类

创建规则自身的类之前,将向项目添加一个访问器类和一个帮助器类。

提示

这些类对于创建其他自定义规则可能很有用。

您必须定义的第一个类为派生自 TSqlConcreteFragmentVisitor 的 WaitForDelayVisitor 类。 此类提供对模型中的 WAITFOR DELAY 语句的访问。

定义 WaitForDelayVisitor 类

  1. 在**“解决方案资源管理器”**中,选择 SampleRules 项目。

  2. 在**“项目”菜单上选择“添加类”**。

    将显示**“添加新项”**对话框。

  3. 在**“名称”文本框中,键入 WaitForDelayVisitor.cs,然后单击“添加”**按钮。

    此时 WaitForDelayVisitor.cs 文件将添加到**“解决方案资源管理器”**的项目中。

  4. 打开 WaitForDelayVisitor.cs 文件,然后更新内容以匹配以下代码:

    using System.Collections.Generic;
    using Microsoft.Data.Schema.ScriptDom.Sql;
    
    namespace SampleRules
    {
        class WaitForDelayVistor
        {
        }
    }
    
  5. 在类声明中,将访问修饰符更改为内部并从 TSqlConcreteFragmentVisitor 派生该类:

        internal class WaitForDelayVisitor : TSqlConcreteFragmentVisitor
        {
        }
    
  6. 添加以下代码以定义 List 成员变量:

            private List<WaitForStatement> _waitForDelayStatments;
    
  7. 通过添加以下代码来定义类构造函数:

            #region ctor
            public WaitForDelayVisitor()
            {
                _waitForDelayStatments = new List<WaitForStatement>();
            }
            #endregion
    
  8. 通过添加以下代码来定义只读 WaitForDelayStatements 属性:

            #region properties
            public List<WaitForStatement> WaitForDelayStatements
            {
                get
                {
                    return _waitForDelayStatments;
                }
            }
            #endregion
    
  9. 通过添加以下代码来重写 ExplicitVisit 方法:

            #region overrides
            public override void ExplicitVisit(WaitForStatement node)
            {
                // We are only interested in WAITFOR DELAY occurrences
                if (node.WaitForOption == WaitForOption.Delay)
                {
                    _waitForDelayStatments.Add(node);
                }
            }
            #endregion
    

    此方法将访问模型中的 WAITFOR 语句,并将指定了 DELAY 选项的 WAITFOR 语句添加到 WAITFOR DELAY 语句的列表中。 此处引用的关键类为 WaitForStatement

  10. 在**“文件”菜单上,单击“保存”**。

第二个类是 SqlRuleUtils.cs,它包含自定义代码分析规则类将使用的某些实用工具方法,稍后将在此演练中的创建自定义代码分析规则类部分创建该规则类。 这些方法包括:

  • GetElementName 用于获取模型元素的已转义的完全限定名称。

  • UpdateProblemPosition:用于计算行和列信息。

  • ReadFileContent:用于从文件读取内容。

  • GetElementSourceFile:用于获取源文件。

  • ComputeLineColumn:用于将偏移量从 ScriptDom 转换为脚本文件中的行和列。

向项目添加 SqlRuleUtils.cs 文件

  1. 在**“解决方案资源管理器”**中,选择 SampleRules 项目。

  2. 在**“项目”菜单上选择“添加类”**。

    将显示**“添加新项”**对话框。

  3. 在**“名称”文本框中,键入 SqlRuleUtils.cs,然后单击“添加”**按钮。

    此时 SqlRuleUtils.cs 文件将添加到**“解决方案资源管理器”**的项目中。

  4. 打开 SqlRuleUtils.cs 文件,并将以下 using 语句添加到文件中:

    using System;
    using System.Diagnostics;
    using System.IO;
    using Microsoft.Data.Schema.SchemaModel;
    using Microsoft.Data.Schema.Sql.SchemaModel;
    using Microsoft.Data.Schema.StaticCodeAnalysis;
    using Microsoft.Data.Schema;
    
    
    namespace SampleRules
    {
    }
    
  5. 在 SqlRuleUtils 类声明中,将访问修饰符更改为公共静态:

        public static class SqlRuleUtils
        {
        }
    
  6. 添加以下代码以创建 GetElementName 方法,该方法使用 SqlSchemaModelISqlModelElement 作为输入参数:

            /// <summary>
            /// Get escaped fully qualified name of a model element 
            /// </summary>
            /// <param name="sm">schema model</param>
            /// <param name="element">model element</param>
            /// <returns>name of the element</returns>
            public static string GetElementName(SqlSchemaModel sm, ISqlModelElement element)
            {
                return sm.DatabaseSchemaProvider.UserInteractionServices.GetElementName(element, ElementNameStyle.EscapedFullyQualifiedName);
            }
    
  7. 添加以下代码以创建 ReadFileContent 方法:

            /// <summary>
            /// Read file content from a file.
            /// </summary>
            /// <param name="filePath"> file path </param>
            /// <returns> file content in a string </returns>
            public static string ReadFileContent(string filePath)
            {
                //  Verify that the file exists first.
                if (!File.Exists(filePath))
                {
                    Debug.WriteLine(string.Format("Cannot find the file: '{0}'", filePath));
                    return string.Empty;
                }
    
                string content;
                using (StreamReader reader = new StreamReader(filePath))
                {
                    content = reader.ReadToEnd();
                    reader.Close();
                }
                return content;
            }
    
  8. 添加以下代码以创建 GetElementSourceFile 方法,该方法使用 IModelElement 作为输入参数,并使用 String 检索文件名。 此方法将 IModelElement 强制转换为 IScriptSourcedModelElement,然后在确定模型元素中的脚本文件路径时使用 ISourceInformation

            /// <summary>
            /// Get the corresponding script file path from a model element.
            /// </summary>
            /// <param name="element">model element</param>
            /// <param name="fileName">file path of the scripts corresponding to the model element</param>
            /// <returns></returns>
            private static Boolean GetElementSourceFile(IModelElement element, out String fileName)
            {
                fileName = null;
    
                IScriptSourcedModelElement scriptSourcedElement = element as IScriptSourcedModelElement;
                if (scriptSourcedElement != null)
                {
                    ISourceInformation elementSource = scriptSourcedElement.PrimarySource;
                    if (elementSource != null)
                    {
                        fileName = elementSource.SourceName;
                    }
                }
    
                return String.IsNullOrEmpty(fileName) == false;
            }
    
  9. 添加以下代码以创建 ComputeLineColumn 方法:

            /// This method converts offset from ScriptDom to line\column in script files.
            /// A line is defined as a sequence of characters followed by a carriage return ("\r"), 
            /// a line feed ("\n"), or a carriage return immediately followed by a line feed. 
            public static bool ComputeLineColumn(string text, Int32 offset, Int32 length,
                                                out Int32 startLine, out Int32 startColumn, out Int32 endLine, out Int32 endColumn)
            {
                const char LF = '\n';
                const char CR = '\r';
    
                // Setting the initial value of line and column to 0 since VS auto-increments by 1.
                startLine = 0;
                startColumn = 0;
                endLine = 0;
                endColumn = 0;
    
                int textLength = text.Length;
    
                if (offset < 0 || length < 0 || offset + length > textLength)
                {
                    return false;
                }
    
                for (int charIndex = 0; charIndex < length + offset; ++charIndex)
                {
                    char currentChar = text[charIndex];
                    Boolean afterOffset = charIndex >= offset;
                    if (currentChar == LF)
                    {
                        ++endLine;
                        endColumn = 0;
                        if (afterOffset == false)
                        {
                            ++startLine;
                            startColumn = 0;
                        }
                    }
                    else if (currentChar == CR)
                    {
                        // CR/LF combination, consuming LF.
                        if ((charIndex + 1 < textLength) && (text[charIndex + 1] == LF))
                        {
                            ++charIndex;
                        }
    
                        ++endLine;
                        endColumn = 0;
                        if (afterOffset == false)
                        {
                            ++startLine;
                            startColumn = 0;
                        }
                    }
                    else
                    {
                        ++endColumn;
                        if (afterOffset == false)
                        {
                            ++startColumn;
                        }
                    }
                }
    
                return true;
            }
    
  10. 添加以下代码以创建 UpdateProblemPosition 方法,该方法使用 DataRuleProblem 作为输入参数:

            /// <summary>
            /// Compute the start Line/Col and the end Line/Col to update problem info
            /// </summary>
            /// <param name="problem">problem found</param>
            /// <param name="offset">offset of the fragment having problem</param>
            /// <param name="length">length of the fragment having problem</param>
            public static void UpdateProblemPosition(DataRuleProblem problem, int offset, int length)
            {
                if (problem.ModelElement != null)
                {
                    String fileName = null;
                    int startLine = 0;
                    int startColumn = 0;
                    int endLine = 0;
                    int endColumn = 0;
    
                    bool ret = GetElementSourceFile(problem.ModelElement, out fileName);
                    if (ret)
                    {
                        string fullScript = ReadFileContent(fileName);
    
                        if (fullScript != null)
                        {
                            if (ComputeLineColumn(fullScript, offset, length, out startLine, out startColumn, out endLine, out endColumn))
                            {
                                problem.FileName = fileName;
                                problem.StartLine = startLine + 1;
                                problem.StartColumn = startColumn + 1;
                                problem.EndLine = endLine + 1;
                                problem.EndColumn = endColumn + 1;
                            }
                            else
                            {
                                Debug.WriteLine("Could not compute line and column");
                            }
                        }
                    }
                }
            }
    
  11. 在**“文件”菜单上,单击“保存”**。

接下来,您添加一个资源文件,此文件将定义规则名称、规则说明以及规则在规则配置界面中所属的类别。

添加一个资源文件和三个资源字符串

  1. 在**“解决方案资源管理器”**中,选择 SampleRules 项目。

  2. 在**“项目”菜单上选择“添加新项”**。

    将显示**“添加新项”**对话框。

  3. 在**“已安装的模板”列表中,单击“常规”**。

  4. 在细节窗格中,单击**“资源文件”**。

  5. 在**“名称”**中,键入 SampleRuleResource.resx。

    这将显示资源编辑器,其中尚未定义任何资源。

  6. 定义三个资源字符串,如下所示:

    名称

    AvoidWaitForDelay_ProblemDescription

    在 {0} 中找到了 WAITFOR DELAY 语句。

    AvoidWaitForDelay_RuleName

    避免在存储过程、函数和触发器中使用 WaitFor Delay 语句。

    CategorySamples

    SamplesCategory

  7. 在**“文件”菜单上,单击“保存 SampleRuleResource.resx”**。

接下来,定义一个引用资源文件中的资源的类,这些资源供 Visual Studio 用来显示有关用户界面中的规则的信息。

定义 SampleConstants 类

  1. 在**“解决方案资源管理器”**中,选择 SampleRules 项目。

  2. 在**“项目”菜单上选择“添加类”**。

    将显示**“添加新项”**对话框。

  3. 在**“名称”文本框中,键入 SampleRuleConstants.cs,然后单击“添加”**按钮。

    此时 SampleRuleConstants.cs 文件将添加到**“解决方案资源管理器”**的项目中。

  4. 打开 SampleRuleConstants.cs 文件,并将以下 using 语句添加到文件中:

    namespace SampleRules
    {
        internal class SampleConstants
        {
            public const string NameSpace = "SamplesRules";
            public const string ResourceBaseName = "SampleRules.SampleRuleResource";
            public const string CategorySamples = "CategorySamples";
    
            public const string AvoidWaitForDelayRuleId = "SR1004";
            public const string AvoidWaitForDelay_RuleName = "AvoidWaitForDelay_RuleName";
            public const string AvoidWaitForDelay_ProblemDescription = "AvoidWaitForDelay_ProblemDescription";
        }
    }
    
  5. 在**“文件”菜单上,单击“保存”**。

创建自定义代码分析规则类

现在已添加了自定义代码分析规则将使用的帮助器类,接下来将创建自定义规则类,并将其命名为 AvoidWaitForDelayRule。 AvoidWaitForDelayRule 自定义规则将用于帮助数据库开发人员避免在存储过程、触发器和函数中出现 WAITFOR DELAY 语句。

创建 AvoidWaitForDelayRule 类

  1. 在**“解决方案资源管理器”**中,选择 SampleRules 项目。

  2. 在**“项目”菜单上,选择“新建文件夹”**。

  3. 此时将在**“解决方案资源管理器”**中显示一个新文件夹。 将文件夹命名为 AvoidWaitForDelayRule。

  4. 在**“解决方案资源管理器”**中,确认选择了 AvoidWaitForDelayRule 文件夹。

  5. 在**“项目”菜单上选择“添加类”**。

    将显示**“添加新项”**对话框。

  6. 在**“名称”文本框中,键入 AvoidWaitForDelayRule.cs,然后单击“添加”**按钮。

    此时 AvoidWaitForDelayRule.cs 文件将添加到**“解决方案资源管理器”**中项目的 AvoidWaitForDelayRule 文件夹。

  7. 打开 AvoidWaitForDelayRule.cs 文件,并将以下 using 语句添加到文件中:

    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Globalization;
    using Microsoft.Data.Schema.Extensibility;
    using Microsoft.Data.Schema.SchemaModel;
    using Microsoft.Data.Schema.ScriptDom.Sql;
    using Microsoft.Data.Schema.Sql.SchemaModel;
    using Microsoft.Data.Schema.Sql;
    using Microsoft.Data.Schema.StaticCodeAnalysis;
    namespace SampleRules
    {
        public class AvoidWaitForDelayRule
        {
        }
    }
    

    提示

    您必须将命名空间名称从 SampleRules.AvoidWaitForDelayRule 更改为 SampleRules。

  8. 在 AvoidWaitForDelayRule 类声明中,将访问修饰符更改为公共:

        /// <summary>
        /// This is a SQL rule which returns a warning message 
        /// whenever there is a WAITFOR DELAY statement appears inside a subroutine body. 
        /// This rule only applies to SQL stored procedures, functions and triggers.
        /// </summary>
        public class AvoidWaitForDelayRule
    
  9. StaticCodeAnalysisRule 基类派生 AvoidWaitForDelayRule 类:

        public class AvoidWaitForDelayRule : StaticCodeAnalysisRule
    
  10. DatabaseSchemaProviderCompatibilityAttributeDataRuleAttributeSupportedElementTypeAttribute 添加到类中。 有关功能扩展兼容性的更多信息,请参见扩展 Visual Studio 的数据库功能

        [DatabaseSchemaProviderCompatibility(typeof(SqlDatabaseSchemaProvider))]
        [DataRuleAttribute(
            SampleConstants.NameSpace,
            SampleConstants.AvoidWaitForDelayRuleId,
            SampleConstants.ResourceBaseName,
            SampleConstants.AvoidWaitForDelay_RuleName,
            SampleConstants.CategorySamples,
            DescriptionResourceId = SampleConstants.AvoidWaitForDelay_ProblemDescription)]
        [SupportedElementType(typeof(ISqlProcedure))]
        [SupportedElementType(typeof(ISqlTrigger))]
        [SupportedElementType(typeof(ISqlFunction))]
        public class AvoidWaitForDelayRule : StaticCodeAnalysisRule
    

    DataRuleAttribute 指定当配置数据库代码分析规则时显示在 Visual Studio 中的信息。 SupportedElementTypeAttribute 定义要将此规则应用于的元素的类型。 在此示例中,规则将应用于存储过程、触发器和函数。

  11. 添加 Analyze 方法的重写,它使用 DataRuleSettingDataRuleExecutionContext 作为输入参数。 此方法返回一个潜在问题列表。

    此方法从上下文参数获取 IModelElementTSqlFragmentSqlSchemaModelISqlModelElement 是从模型元素获取的。 然后,使用 WaitForDelayVisitor 类获取一个包含模型中所有 WAITFOR DELAY 语句的列表。

    为该列表中的每个 WaitForStatement 创建了一个 DataRuleProblem

            #region Overrides
            /// <summary>
            /// Analyze the model element
            /// </summary>
            public override IList<DataRuleProblem> Analyze(DataRuleSetting ruleSetting, DataRuleExecutionContext context)
            {
                List<DataRuleProblem> problems = new List<DataRuleProblem>();
    
                IModelElement modelElement = context.ModelElement;
    
                // this rule does not apply to inline table-valued function
                // we simply do not return any problem
                if (modelElement is ISqlInlineTableValuedFunction)
                {
                    return problems;
                }
    
                // casting to SQL specific 
                SqlSchemaModel sqlSchemaModel = modelElement.Model as SqlSchemaModel;
                Debug.Assert(sqlSchemaModel!=null, "SqlSchemaModel is expected");
    
                ISqlModelElement sqlElement = modelElement as ISqlModelElement;
                Debug.Assert(sqlElement != null, "ISqlModelElement is expected");
    
                // Get ScriptDom for this model element
                TSqlFragment sqlFragment = context.ScriptFragment as TSqlFragment;
                Debug.Assert(sqlFragment != null, "TSqlFragment is expected");
    
                // visitor to get the ocurrences of WAITFOR DELAY statements
                WaitForDelayVisitor visitor = new WaitForDelayVisitor();
                sqlFragment.Accept(visitor);
                List<WaitForStatement> waitforDelayStatements = visitor.WaitForDelayStatements;
    
                // Create problems for each WAITFOR DELAY statement found 
                foreach (WaitForStatement waitForStatement in waitforDelayStatements)
                {
                    DataRuleProblem problem = new DataRuleProblem(this,
                                                String.Format(CultureInfo.CurrentCulture, this.RuleProperties.Description, SqlRuleUtils.GetElementName(sqlSchemaModel, sqlElement)),
                                                sqlElement);
    
                    SqlRuleUtils.UpdateProblemPosition(problem, waitForStatement.StartOffset, waitForStatement.FragmentLength);
                    problems.Add(problem);
                }
    
                return problems;
            }
    
            #endregion    
    
    
  12. 在**“文件”菜单上,单击“保存”**。

接下来,将生成项目。

生成项目

  • 从**“生成”菜单中,单击“生成解决方案”**。

接下来,将收集项目中生成的程序集信息,其中包括版本、区域性和 PublicKeyToken。

收集程序集信息

  1. 在**“视图”菜单上,单击“其他窗口”,然后单击“命令窗口”打开“命令”**窗口。

  2. 在**“命令”**窗口中,键入以下代码。 将 FilePath 替换为已编译的 .dll 文件的路径和文件名。 在路径和文件名的两侧加双引号。

    提示

    默认情况下,FilePath 为 Projects\SampleRules\SampleRules\bin\Debug\YourDLL 或 Projects\SampleRules\SampleRules\bin\Release\YourDLL。

    ? System.Reflection.Assembly.LoadFrom(@"FilePath")
    
  3. 按 Enter。 此时该行应类似于以下内容,其中含有您的特定 PublicKeyToken:

    "SampleRules, Version=1.0.0.0, Culture=neutral, PublicKeyToken=nnnnnnnnnnnnnnnn"
    

    记下或复制此程序集信息;下一过程中将使用这些信息。

接下来,将使用上一过程中收集的程序集信息创建 XML 文件。

创建 XML 文件

  1. 在**“解决方案资源管理器”**中,选择 SampleRules 项目。

  2. 在**“项目”菜单上选择“添加新项”**。

  3. 在**“模板”窗格中,找到并选择“XML 文件”**项。

  4. 在**“名称”文本框中,键入 SampleRules.Extensions.xml,然后单击“添加”**按钮。

    此时 SampleRules.Extensions.xml 文件将添加到**“解决方案资源管理器”**的项目中。

  5. 打开 SampleRules.Extensions.xml 文件,将其更新以匹配以下 XML。 将版本、区域性和 PublicKeyToken 值替换为上一过程中检索的这些值。

    <?xml version="1.0" encoding="utf-8"?>
    <extensions assembly=""
                version="1" xmlns="urn:Microsoft.Data.Schema.Extensions"
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                xsi:schemaLocation="urn:Microsoft.Data.Schema.Extensions Microsoft.Data.Schema.Extensions.xsd">
    
      <extension type="SampleRules.AvoidWaitForDelayRule" assembly="SampleRules, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b4deb9b383d021b0" enabled="true"/>
    </extensions> 
    
  6. 在**“文件”菜单上,单击“保存”**。

接下来,要将程序集信息和 XML 文件复制到 Extensions 目录。 Visual Studio 启动时,将识别 Microsoft Visual Studio 10.0\VSTSDB\Extensions 目录和子目录中的任何扩展,并注册这些扩展以用于会话中。

将程序集信息和 XML 文件复制到 Extensions 目录

  1. 在 Microsoft Visual Studio 10.0\VSTSDB\Extensions\ 目录中创建一个新文件夹,名为 CustomRules。

  2. 将 SampleRules.dll 程序集文件从 Projects\SampleRules\SampleRules\bin\Debug\ 目录复制到已创建的 Microsoft Visual Studio 10.0\VSTSDB\Extensions\CustomRules 目录。

  3. 将 SampleRules.Extensions.xml 文件从 Projects\SampleRules\SampleRules\ 目录复制到已创建的 Microsoft Visual Studio 10.0\VSTSDB\Extensions\CustomRules 目录。

    提示

    最佳做法是将扩展程序集放在 Microsoft Visual Studio 10.0\VSTSDB\Extensions 目录下的文件夹中。 这样将帮助您识别随产品包括了哪些扩展,以及哪些扩展是您自定义创建的。 建议使用文件夹将扩展按特定类别进行组织。

接下来,将启动 Visual Studio 的新会话并创建数据库项目。

启动 Visual Studio 的新会话并创建数据库项目

  1. 再启动 Visual Studio 的一个会话。

  2. 在**“文件”菜单上,单击“新建”,然后单击“项目”**。

  3. 在**“新建项目”对话框的“已安装的模板”列表中,展开“数据库项目”节点,然后单击“SQL Server”**。

  4. 在细节窗格中,选择**“SQL Server 2008 数据库项目”**。

  5. 在**“名称”文本框中,键入 SampleRulesDB,然后单击“确定”**。

最后,将看到新规则显示在 SQL Server 项目中。

查看新的 AvoidWaitForRule 代码分析规则

  1. 在**“解决方案资源管理器”**中,选择 SampleRulesDB 项目。

  2. 在**“项目”菜单上,单击“属性”**。

    此时将显示 SampleRulesDB 属性页。

  3. 单击**“代码分析”**。

    应该看到一个名为 CategorySamples 的新类别。

  4. 展开 CategorySamples。

    应该看到**“SR1004: 避免在存储过程、触发器和函数中出现 WAITFOR DELAY 语句”**。

请参见

任务

如何:注册和管理功能扩展

如何:将自定义功能扩展分发给团队成员

参考

ISqlProcedure

ISqlTrigger

ISqlFunction

ISqlInlineTableValuedFunction

概念

扩展 Visual Studio 的数据库功能

分析数据库代码以提高代码质量

使用代码分析来分析托管代码质量