/// <summary> /// Checks if an object is: /// - Named /// - Starts with a letter or digit. This filters our parameters starting with '@', but may filter out other /// objects you wish to test for. This is where you would extend the logic for more advanced cases /// - The first letter is not uppercase. /// </summary> private void CheckIfCapitalized(TSqlObject tSqlObject, List <SqlRuleProblem> problems) { ObjectIdentifier name = tSqlObject.Name; if (name != null && name.HasName && name.Parts.Count > 0) // This check is equivalent to name.HasHame, including in case you don't trust the framework and want to verify yourself { string actualName = name.Parts[name.Parts.Count - 1]; if (!string.IsNullOrEmpty(actualName) && Char.IsLetterOrDigit(actualName[0]) && !Char.IsUpper(actualName[0])) { string description = string.Format(CultureInfo.CurrentCulture, RuleResources.CapitalizedNames_ProblemDescription, _model.DisplayServices.GetElementName(tSqlObject, ElementNameStyle.EscapedFullyQualifiedName)); // Name fragment would have more precise location information than the overall object. // This can be null, in which case the object's position will be used. // note that the current implementation does not work for non-top level types as it // relies on the TSqlModelUtils.TryGetFragmentForAnalysis() method which doesn't support these. TSqlFragment nameFragment = TsqlScriptDomUtils.LookupSchemaObjectName(tSqlObject); problems.Add(new SqlRuleProblem(description, tSqlObject, nameFragment)); } } }
/// <summary> // Views must be schema bound if they reference a memory optimized table /// </summary> private static void ValidateViewHasSchemaBinding(SqlRuleExecutionContext context, TSqlObject view, TSqlObject table, IList <SqlRuleProblem> problems) { if (!view.GetProperty <bool>(View.WithSchemaBinding)) { string description = string.Format(CultureInfo.CurrentCulture, RuleResources.ViewsOnMemoryOptimizedTable_SchemaBindingProblemDescription, RuleUtils.GetElementName(context, view), RuleUtils.GetElementName(context, table)); TSqlFragment nameFragment = TsqlScriptDomUtils.LookupSchemaObjectName(view); problems.Add(new SqlRuleProblem(description, view, nameFragment)); } }
/// <summary> /// No Indexes of any kind are allowed on Views that reference a memory optimized table. /// </summary> private void ValidateViewHasNoIndexes(SqlRuleExecutionContext context, TSqlObject view, TSqlObject table, IList <SqlRuleProblem> problems) { foreach (TSqlObject index in view.GetReferencing(Index.IndexedObject)) { string description = string.Format(CultureInfo.CurrentCulture, RuleResources.ViewsOnMemoryOptimizedTable_IndexProblemDescription, RuleUtils.GetElementName(context, index), RuleUtils.GetElementName(context, view), RuleUtils.GetElementName(context, table)); TSqlFragment nameFragment = TsqlScriptDomUtils.LookupSchemaObjectName(index); // Note that nameFragment can be null - in this case the index's position information will be used. // This is just a little less precise than pointing to the position of the name for that index problems.Add(new SqlRuleProblem(description, index, nameFragment)); } }
private void CheckNamingConvention(TSqlObject tSqlObject, List <SqlRuleProblem> problems) { ObjectIdentifier name = tSqlObject.Name; if (name != null && name.HasName && name.Parts.Count > 0) // This check is equivalent to name.HasHame, including in case you don't trust the framework and want to verify yourself { string actualName = name.Parts[name.Parts.Count - 1]; switch (tSqlObject.ObjectType.Name) { case "View": { if (!string.IsNullOrEmpty(actualName) && !actualName.StartsWith("vw_")) { string description = string.Format(CultureInfo.CurrentCulture, RuleResources.NamingConventions_ProblemDescription, _model.DisplayServices.GetElementName(tSqlObject, ElementNameStyle.EscapedFullyQualifiedName)); // Name fragment would have more precise location information than the overall object. // This can be null, in which case the object's position will be used. // note that the current implementation does not work for non-top level types as it // relies on the TSqlModelUtils.TryGetFragmentForAnalysis() method which doesn't support these. TSqlFragment nameFragment = TsqlScriptDomUtils.LookupSchemaObjectName(tSqlObject); problems.Add(new SqlRuleProblem(description, tSqlObject, nameFragment)); } break; } case "Procedure": { if (!string.IsNullOrEmpty(actualName) && !actualName.StartsWith("usp_")) { string description = string.Format(CultureInfo.CurrentCulture, RuleResources.NamingConventions_ProblemDescription, _model.DisplayServices.GetElementName(tSqlObject, ElementNameStyle.EscapedFullyQualifiedName)); // Name fragment would have more precise location information than the overall object. // This can be null, in which case the object's position will be used. // note that the current implementation does not work for non-top level types as it // relies on the TSqlModelUtils.TryGetFragmentForAnalysis() method which doesn't support these. TSqlFragment nameFragment = TsqlScriptDomUtils.LookupSchemaObjectName(tSqlObject); problems.Add(new SqlRuleProblem(description, tSqlObject, nameFragment)); } break; } case "PrimaryKeyConstraint": { if (!string.IsNullOrEmpty(actualName) && !actualName.StartsWith("pk_")) { string description = string.Format(CultureInfo.CurrentCulture, RuleResources.NamingConventions_ProblemDescription, _model.DisplayServices.GetElementName(tSqlObject, ElementNameStyle.EscapedFullyQualifiedName)); // Name fragment would have more precise location information than the overall object. // This can be null, in which case the object's position will be used. // note that the current implementation does not work for non-top level types as it // relies on the TSqlModelUtils.TryGetFragmentForAnalysis() method which doesn't support these. TSqlFragment nameFragment = TsqlScriptDomUtils.LookupSchemaObjectName(tSqlObject); problems.Add(new SqlRuleProblem(description, tSqlObject, nameFragment)); } break; } case "ForeignKeyConstraint": { if (!string.IsNullOrEmpty(actualName) && !actualName.StartsWith("fk_")) { string description = string.Format(CultureInfo.CurrentCulture, RuleResources.NamingConventions_ProblemDescription, _model.DisplayServices.GetElementName(tSqlObject, ElementNameStyle.EscapedFullyQualifiedName)); // Name fragment would have more precise location information than the overall object. // This can be null, in which case the object's position will be used. // note that the current implementation does not work for non-top level types as it // relies on the TSqlModelUtils.TryGetFragmentForAnalysis() method which doesn't support these. TSqlFragment nameFragment = TsqlScriptDomUtils.LookupSchemaObjectName(tSqlObject); problems.Add(new SqlRuleProblem(description, tSqlObject, nameFragment)); } break; } case "CheckConstraint": { if (!string.IsNullOrEmpty(actualName) && !actualName.StartsWith("ck_")) { string description = string.Format(CultureInfo.CurrentCulture, RuleResources.NamingConventions_ProblemDescription, _model.DisplayServices.GetElementName(tSqlObject, ElementNameStyle.EscapedFullyQualifiedName)); // Name fragment would have more precise location information than the overall object. // This can be null, in which case the object's position will be used. // note that the current implementation does not work for non-top level types as it // relies on the TSqlModelUtils.TryGetFragmentForAnalysis() method which doesn't support these. TSqlFragment nameFragment = TsqlScriptDomUtils.LookupSchemaObjectName(tSqlObject); problems.Add(new SqlRuleProblem(description, tSqlObject, nameFragment)); } break; } case "DefaultConstraint": { if (!string.IsNullOrEmpty(actualName) && !actualName.StartsWith("df_")) { string description = string.Format(CultureInfo.CurrentCulture, RuleResources.NamingConventions_ProblemDescription, _model.DisplayServices.GetElementName(tSqlObject, ElementNameStyle.EscapedFullyQualifiedName)); // Name fragment would have more precise location information than the overall object. // This can be null, in which case the object's position will be used. // note that the current implementation does not work for non-top level types as it // relies on the TSqlModelUtils.TryGetFragmentForAnalysis() method which doesn't support these. TSqlFragment nameFragment = TsqlScriptDomUtils.LookupSchemaObjectName(tSqlObject); problems.Add(new SqlRuleProblem(description, tSqlObject, nameFragment)); } break; } case "Synonym": { if (!string.IsNullOrEmpty(actualName) && !actualName.StartsWith("syn_")) { string description = string.Format(CultureInfo.CurrentCulture, RuleResources.NamingConventions_ProblemDescription, _model.DisplayServices.GetElementName(tSqlObject, ElementNameStyle.EscapedFullyQualifiedName)); // Name fragment would have more precise location information than the overall object. // This can be null, in which case the object's position will be used. // note that the current implementation does not work for non-top level types as it // relies on the TSqlModelUtils.TryGetFragmentForAnalysis() method which doesn't support these. TSqlFragment nameFragment = TsqlScriptDomUtils.LookupSchemaObjectName(tSqlObject); problems.Add(new SqlRuleProblem(description, tSqlObject, nameFragment)); } break; } case "DmlTrigger": { if (!string.IsNullOrEmpty(actualName) && !actualName.StartsWith("trg_")) { string description = string.Format(CultureInfo.CurrentCulture, RuleResources.NamingConventions_ProblemDescription, _model.DisplayServices.GetElementName(tSqlObject, ElementNameStyle.EscapedFullyQualifiedName)); // Name fragment would have more precise location information than the overall object. // This can be null, in which case the object's position will be used. // note that the current implementation does not work for non-top level types as it // relies on the TSqlModelUtils.TryGetFragmentForAnalysis() method which doesn't support these. TSqlFragment nameFragment = TsqlScriptDomUtils.LookupSchemaObjectName(tSqlObject); problems.Add(new SqlRuleProblem(description, tSqlObject, nameFragment)); } break; } } } }