Demonstra Passo a passo: Estender a compilação de projeto de banco de dados para gerar estatísticas de modelo
Você pode criar um colaborador de compilação para executar ações personalizadas quando você constrói um projeto de banco de dados. Esta explicação passo a passo, você pode criar um colaborador de compilação chamado ModelStatistics que produz estatísticas a partir do modelo de banco de dados quando você constrói um projeto de banco de dados. Porque este Colaborador de compilação usa parâmetros quando você constrói, algumas etapas adicionais são necessárias.
Esta explicação passo a passo, você irá realizar as seguintes tarefas principais:
Criar um colaborador de compilação
Instalar o colaborador de compilação
Teste seu colaborador de compilação
Pré-requisitos
Para completar este passo a passo, são necessários os seguintes componentes:
Você deve ter instalado Visual Studio 2010 Premium ou Visual Studio 2010 Ultimate.
Você deve ter um projeto de banco de dados que contém objetos de banco de dados
Observação |
---|
Esta explicação passo a passo destina-se a usuários que já estejam familiarizados com os recursos de banco de dados do Visual Studio Premium. Você também deve estar familiarizado com o basic Visual Studio os conceitos, como criar uma biblioteca de classe e de como usar o editor de código para adicionar código para uma classe. |
Criar um colaborador de compilação
Para criar um colaborador de compilação, você deve executar as seguintes tarefas:
Crie um projeto de biblioteca de classe e adicionar referências necessárias
Definir uma classe chamada ModelStatistics que herda deBuildContributor
Substituir os métodos OnPopulateArguments e OnExecute
Adicionar alguns métodos de auxiliar particular
Compilar o assembly resultante
Observação |
---|
Este colaborador produzirá somente quando um projeto de banco de dados é criado usando MSBuild. O relatório está desativado por padrão, mas você pode substituí-la, fornecendo uma propriedade na linha de comando do MSBuild. Para obter um exemplo de como habilitar a saída na janela Saída, consulte Demonstra Passo a passo: Estender a implantação de projeto de banco de dados para analisar o plano de implantação. |
Para criar um projeto de biblioteca de classe
Criar um Visual Basic ou Visual C#, o projeto de biblioteca de classe denominado MyBuildContributor.
No Solution Explorer, clique com o botão direito no nó do projeto e clique em Adicionar referência de.
Clique na .NET guia.
Realce o Microsoft.Data.Schema e Microsoft.Data.Schema.Sql entradas e clique em OK.
Em seguida, começar a adicionar código à classe.
Para definir a classe ModelStatistics
No editor de código, atualizar o arquivo Class1. cs para coincidir com o seguinte using ou Imports instruções:
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Xml.Linq; using Microsoft.Data.Schema; using Microsoft.Data.Schema.Build; using Microsoft.Data.Schema.Extensibility; using Microsoft.Data.Schema.SchemaModel; using Microsoft.Data.Schema.Sql;
Imports System Imports System.Collections.Generic Imports System.IO Imports System.Linq Imports System.Xml.Linq Imports Microsoft.Data.Schema Imports Microsoft.Data.Schema.Build Imports Microsoft.Data.Schema.Extensibility Imports Microsoft.Data.Schema.SchemaModel Imports Microsoft.Data.Schema.Sql
Atualize a definição de classe para coincidir com o seguinte:
/// <summary> /// The ModelStatistics class demonstrates /// how you can create a class that inherits BuildContributor /// to perform actions when you build a database project. /// </summary> [DatabaseSchemaProviderCompatibility(typeof(SqlDatabaseSchemaProvider))] public sealed class ModelStatistics : BuildContributor { }
''' <summary> ''' The ModelStatistics class demonstrates ''' how you can create a class that inherits BuildContributor ''' to perform actions when you build a database project. ''' </summary> <DatabaseSchemaProviderCompatibility(GetType(SqlDatabaseSchemaProvider))> _ Public NotInheritable Class ModelStatistics Inherits BuildContributor End Class
Agora você ter definido seu colaborador de compilação e usado o atributo para indicar que este colaborador é compatível com qualquer provedor de esquema de banco de dados que herda de SqlDatabaseSchemaProvider.
Em seguida, adicione os seguintes membros. Você usará os membros para habilitar este provedor de aceitar parâmetros de linha de comando de compilação:
private const string GenerateModelStatistics = "GenerateModelStatistics"; private const string SortModelStatisticsBy = "SortModelStatisticsBy"; private const string GenerateModelStatisticsVariable = "$(" + GenerateModelStatistics + ")"; private const string SortModelStatisticsByVariable = "$(" + SortModelStatisticsBy + ")"; private enum SortBy { None, Name, Value }; private static Dictionary<string, SortBy> SortByMap = new Dictionary<string, SortBy>(StringComparer.OrdinalIgnoreCase) { { "none", SortBy.None }, { "name", SortBy.Name }, { "value", SortBy.Value }, }; private SortBy _sortBy = SortBy.None;
Private Const GenerateModelStatistics As String = "GenerateModelStatistics" Private Const SortModelStatisticsBy As String = "SortModelStatisticsBy" Private Const GenerateModelStatisticsVariable As String = "$(" & GenerateModelStatistics & ")" Private Const SortModelStatisticsByVariable As String = "$(" & SortModelStatisticsBy & ")" Private Enum SortBy None Name Value End Enum '' SortByMap maps the command-line parameter string values to the enumeration values Private Shared SortByMap As New Dictionary(Of String, SortBy)(StringComparer.OrdinalIgnoreCase) Private _sortBy As SortBy = SortBy.None
Estes membros ativam o usuário especificar se as estatísticas devem ser geradas usando a opção de GenerateModelStatistics e especificar como as estatísticas devem ser ordenadas, especificando a opção SortModelStatisticsBy.
Em seguida, substituir o OnPopulateArguments método para criar a lista de argumentos para passar para o colaborador de compilação.
Para substituir o OnPopulateArguments
Adicione que o seguinte método à classe ModelStatistics de substituir:
/// <summary> /// Override the OnPopulateArgument method to build a list of arguments from the input /// configuration information. /// </summary> protected override IList<ContributorArgumentConfiguration> OnPopulateArguments() { List<ContributorArgumentConfiguration> args = new List<ContributorArgumentConfiguration>(); args.Add(new ContributorArgumentConfiguration( name: GenerateModelStatistics, value: GenerateModelStatisticsVariable, condition: null)); args.Add(new ContributorArgumentConfiguration( name: SortModelStatisticsBy, value: SortModelStatisticsByVariable, condition: null)); return args; }
''' <summary> ''' Override the OnPopulateArgument method to build a list of arguments from the input ''' configuration information. ''' </summary> Protected Overrides Function OnPopulateArguments() As System.Collections.Generic.IList(Of Microsoft.Data.Schema.Build.ContributorArgumentConfiguration) Dim args As List(Of ContributorArgumentConfiguration) = New List(Of ContributorArgumentConfiguration) args.Add(New ContributorArgumentConfiguration(name:=GenerateModelStatistics, _ value:=GenerateModelStatisticsVariable, _ condition:=Nothing)) args.Add(New ContributorArgumentConfiguration(name:=SortModelStatisticsBy, _ value:=SortModelStatisticsByVariable, _ condition:=Nothing)) Return MyBase.OnPopulateArguments() End Function
Você cria dois ContributorArgumentConfiguration objetos e adicioná-los à lista de argumentos.
Em seguida, você pode substituir o método OnExecute para adicionar o código que você deseja executar quando um projeto de banco de dados é criado.
Para substituir o OnExecute
Adicione o seguinte método à sua classe de ModelStatistics:
/// <summary> /// Override the OnExecute method to perform actions when you build a database project. /// </summary> protected override void OnExecute(BuildContributorContext context, ErrorManager errorsContainer) { // handle related arguments, passed in as part of // the context information. bool generateModelStatistics; ParseArguments(context.Arguments, errorsContainer, out generateModelStatistics); // Only generate statistics if requested to do so if (generateModelStatistics) { // First, output model-wide information, such // as the type of database schema provider (DSP) // and the collation. List<DataSchemaError> args = new List<DataSchemaError>(); args.Add(new DataSchemaError(" ", ErrorSeverity.Message)); args.Add(new DataSchemaError("Model Statistics:", ErrorSeverity.Message)); args.Add(new DataSchemaError("=================", ErrorSeverity.Message)); args.Add(new DataSchemaError(" ", ErrorSeverity.Message)); errorsContainer.Add(args, ErrorManager.DefaultCategory); var model = context.Model; // Start building up the XML that will later // be serialized. var xRoot = new XElement("ModelStatistics"); SummarizeModelInfo(model, xRoot, errorsContainer); // First, count the elements that are contained // in this model. var elements = model.GetElements(typeof(IModelElement), ModelElementQueryFilter.Internal); Summarize(elements, element => element.ElementClass.ClassName, "Internal Elements", xRoot, errorsContainer); // Now, count the elements that are defined in // another model. Examples include built-in types, // roles, filegroups, assemblies, and any // referenced objects from another database. elements = model.GetElements(typeof(IModelElement), ModelElementQueryFilter.External); Summarize(elements, element => element.ElementClass.ClassName, "External Elements", xRoot, errorsContainer); // Now, count the number of each type // of relationship in the model. SurveyRelationships(model, xRoot, errorsContainer); // Count the various types of annotations // in the model. var annotations = model.GetAllAnnotations(); Summarize(annotations, anno => anno.AnnotationClass.ClassName, "Annotations", xRoot, errorsContainer); // finally, count any types of custom data // defined for the model. var customData = model.GetCustomData(); Summarize(customData, custom => custom.Category, "Custom Data", xRoot, errorsContainer); // Determine where the user wants to save // the serialized XML file. string outDir; if (context.Arguments.TryGetValue("OutDir", out outDir) == false) { outDir = "."; } var filePath = Path.Combine(outDir, "ModelStatistics.xml"); // Save the XML file and tell the user // where it was saved. xRoot.Save(filePath); DataSchemaError resultArg = new DataSchemaError("Result was saved to " + filePath, ErrorSeverity.Message); errorsContainer.Add(resultArg, ErrorManager.BuildCategory); } }
''' <summary> ''' Override the OnExecute method to perform actions when you build a database project. ''' </summary> Protected Overloads Overrides Sub OnExecute(ByVal context As BuildContributorContext, ByVal errorsContainer As ErrorManager) ' handle related arguments, passed in as part of ' the context information. Dim generateModelStatistics As Boolean ParseArguments(context.Arguments, errorsContainer, generateModelStatistics) ' Only generate statistics if requested to do so If generateModelStatistics Then ' First, output model-wide information, such ' as the type of database schema provider (DSP) ' and the collation. Dim args As New List(Of DataSchemaError)() args.Add(New DataSchemaError(" ", ErrorSeverity.Message)) args.Add(New DataSchemaError("Model Statistics:", ErrorSeverity.Message)) args.Add(New DataSchemaError("=================", ErrorSeverity.Message)) args.Add(New DataSchemaError(" ", ErrorSeverity.Message)) errorsContainer.Add(args, ErrorManager.DefaultCategory) Dim model = context.Model ' Start building up the XML that will later ' be serialized. Dim xRoot = New XElement("ModelStatistics") SummarizeModelInfo(model, xRoot, errorsContainer) ' First, count the elements that are contained ' in this model. Dim elements = model.GetElements(GetType(IModelElement), ModelElementQueryFilter.Internal) Summarize(elements, Function(element) element.ElementClass.ClassName, "Internal Elements", xRoot, errorsContainer) ' Now, count the elements that are defined in ' another model. Examples include built-in types, ' roles, filegroups, assemblies, and any ' referenced objects from another database. elements = model.GetElements(GetType(IModelElement), ModelElementQueryFilter.External) Summarize(elements, Function(element) element.ElementClass.ClassName, "External Elements", xRoot, errorsContainer) ' Now, count the number of each type ' of relationship in the model. SurveyRelationships(model, xRoot, errorsContainer) ' Count the various types of annotations ' in the model. Dim annotations = model.GetAllAnnotations() Summarize(annotations, Function(anno) anno.AnnotationClass.ClassName, "Annotations", xRoot, errorsContainer) ' finally, count any types of custom data ' defined for the model. Dim customData = model.GetCustomData() Summarize(customData, Function([custom]) [custom].Category, "Custom Data", xRoot, errorsContainer) ' Determine where the user wants to save ' the serialized XML file. Dim outDir As String If context.Arguments.TryGetValue("OutDir", outDir) = False Then outDir = "." End If Dim filePath = Path.Combine(outDir, "ModelStatistics.xml") ' Save the XML file and tell the user ' where it was saved. xRoot.Save(filePath) Dim resultArg As New DataSchemaError("Result was saved to " & filePath, ErrorSeverity.Message) errorsContainer.Add(resultArg, ErrorManager.BuildCategory) End If End Sub
O método OnExecute é passado um BuildContributorContext criação de objeto que fornece acesso a quaisquer argumentos especificados, o modelo de banco de dados, propriedades e arquivos de extensão. Neste exemplo, podemos recuperar o modelo e, em seguida, chamar funções auxiliares para a saída de informações sobre o modelo. Também é passado para o método um ErrorManager para usar para relatar quaisquer erros que ocorram.
Tipos adicionais e os métodos de interesse incluem o seguinte: DataSchemaModel, ModelStore, GetElements, GetAllAnnotations, GetCustomData , and ModelElement.
Em seguida, você pode definir os métodos auxiliares que examinar os detalhes do modelo.
Para adicionar métodos auxiliares que geram as estatísticas
Primeiro, adicione os esqueletos dos quatro métodos auxiliares, adicionando o seguinte código:
/// <summary> /// Examine the arguments provided by the user /// to determine if model statistics should be generated /// and, if so, how the results should be sorted. /// </summary> private void ParseArguments(IDictionary<string, string> arguments, ErrorManager errorsContainer, out bool generateModelStatistics) { } /// <summary> /// Retrieve the database schema provider for the /// model and the collation of that model. /// Results are output to the console and added to the XML /// being constructed. /// </summary> private static void SummarizeModelInfo(DataSchemaModel model, XElement xContainer, ErrorManager errorsContainer) { } /// <summary> /// For a provided list of model elements, count the number /// of elements for each class name, sorted as specified /// by the user. /// Results are output to the console and added to the XML /// being constructed. /// </summary> private void Summarize<T>(IList<T> set, Func<T, string> groupValue, string category, XElement xContainer, ErrorManager errorsContainer) { } /// <summary> /// Iterate over all model elements, counting the /// styles and types for relationships that reference each /// element /// Results are output to the console and added to the XML /// being constructed. /// </summary> private static void SurveyRelationships(DataSchemaModel model, XElement xContainer, ErrorManager errorsContainer) { } /// <summary> /// Performs the actual output for this contributor, /// writing the specified set of statistics, and adding any /// output information to the XML being constructed. /// </summary> private static void OutputResult<T>(string category, Dictionary<string, T> statistics, XElement xContainer, ErrorManager errorsContainer) { }
''' <summary> ''' This method goes through the provided arguments to the contributor and determines what ''' parameters and parameter values were provided by the user. ''' </summary> Private Sub ParseArguments(ByVal arguments As IDictionary(Of String, String), ByVal errorsContainer As ErrorManager, ByRef generateModelStatistics__1 As Boolean) End Sub ''' <summary> ''' This method collects and outputs information about the model itself. ''' </summary> Private Shared Sub SummarizeModelInfo(ByVal model As DataSchemaModel, ByVal xContainer As XElement, ByVal errorsContainer As ErrorManager) End Sub ''' <summary> ''' This method goes counts the number of elements in specific categories from the provided element list. ''' </summary> Private Sub Summarize(Of T)(ByVal [set] As IList(Of T), ByVal groupValue As Func(Of T, String), ByVal category As String, ByVal xContainer As XElement, ByVal errorsContainer As ErrorManager) End Sub ''' <summary> ''' This method counts the number of relationships of each type that reference elements in the model ''' </summary> Private Shared Sub SurveyRelationships(ByVal model As DataSchemaModel, ByVal xContainer As XElement, ByVal errorsContainer As ErrorManager) End Sub ''' <summary> ''' This method processes the provided data, outputting it to the console and adding the information ''' to the provided XML. ''' </summary> Private Shared Sub OutputResult(Of T)(ByVal category As String, ByVal statistics As Dictionary(Of String, T), ByVal xContainer As XElement, ByVal errorsContainer As ErrorManager) End Sub
Para definir o corpo do método ParseArguments
Adicione o seguinte código ao corpo do método ParseArguments:
// By default, we don't generate model statistics generateModelStatistics = false; // see if the user provided the GenerateModelStatistics // option and if so, what value was it given. string valueString; arguments.TryGetValue(GenerateModelStatistics, out valueString); if (string.IsNullOrWhiteSpace(valueString) == false) { if (bool.TryParse(valueString, out generateModelStatistics) == false) { generateModelStatistics = false; // The value was not valid from the end user DataSchemaError invalidArg = new DataSchemaError( GenerateModelStatistics + "=" + valueString + " was not valid. It can be true or false", ErrorSeverity.Error); errorsContainer.Add(invalidArg, ErrorManager.BuildCategory); return; } } // Only worry about sort order if the user requested // that we generate model statistics. if (generateModelStatistics) { // see if the user provided the sort option and // if so, what value was provided. arguments.TryGetValue(SortModelStatisticsBy, out valueString); if (string.IsNullOrWhiteSpace(valueString) == false) { SortBy sortBy; if (SortByMap.TryGetValue(valueString, out sortBy)) { _sortBy = sortBy; } else { // The value was not valid from the end user DataSchemaError invalidArg = new DataSchemaError( SortModelStatisticsBy + "=" + valueString + " was not valid. It can be none, name, or value", ErrorSeverity.Error); errorsContainer.Add(invalidArg, ErrorManager.BuildCategory); } } }
' By default, we don't generate model statistics generateModelStatistics__1 = False ' see if the user provided the GenerateModelStatistics ' option and if so, what value was it given. Dim valueString As String = "" arguments.TryGetValue(GenerateModelStatistics, valueString) If String.IsNullOrWhiteSpace(valueString) = False Then If Boolean.TryParse(valueString, generateModelStatistics__1) = False Then generateModelStatistics__1 = False ' The value was not valid from the end user Dim invalidArg As New DataSchemaError((GenerateModelStatistics & "=") + valueString & " was not valid. It can be true or false", ErrorSeverity.[Error]) errorsContainer.Add(invalidArg, ErrorManager.BuildCategory) Exit Sub End If End If If SortByMap.Count = 0 Then '' haven't populated the map yet SortByMap.Add("none", SortBy.None) SortByMap.Add("name", SortBy.Name) SortByMap.Add("value", SortBy.Value) End If ' Only worry about sort order if the user requested ' that we generate model statistics. If generateModelStatistics__1 Then ' see if the user provided the sort option and ' if so, what value was provided. arguments.TryGetValue(SortModelStatisticsBy, valueString) If String.IsNullOrWhiteSpace(valueString) = False Then Dim localSortBy As SortBy If SortByMap.TryGetValue(valueString, localSortBy) Then _sortBy = localSortBy Else ' The value was not valid from the end user Dim invalidArg As New DataSchemaError((SortModelStatisticsBy & "=") + valueString & " was not valid. It can be none, name, or value", ErrorSeverity.[Error]) errorsContainer.Add(invalidArg, ErrorManager.BuildCategory) End If End If End If
Tipos e métodos de interesse incluem: ErrorManager e DataSchemaError.
Para definir o corpo do método SummarizeModelInfo
Adicione o seguinte código ao corpo do método SummarizeModelInfo:
// use a Dictionary to accumulate the information // that will later be output. var info = new Dictionary<string, string>(); // Two things of interest: the database schema // provider for the model, and the language id and // case sensitivity of the collation of that // model info.Add("DSP", model.DatabaseSchemaProvider.GetType().Name); info.Add("Collation", string.Format("{0}({1})", model.Collation.Lcid, model.Collation.CaseSensitive ? "CS" : "CI")); // Output the accumulated information and add it to // the XML. OutputResult("Basic model info", info, xContainer, errorsContainer);
' use a Dictionary to accumulate the information ' that will later be output. Dim info = New Dictionary(Of String, String)() ' Two things of interest: the database schema ' provider for the model, and the language id and ' case sensitivity of the collation of that ' model info.Add("DSP", model.DatabaseSchemaProvider.[GetType]().Name) info.Add("Collation", String.Format("{0}({1})", model.Collation.Lcid, If(model.Collation.CaseSensitive, "CS", "CI"))) ' Output the accumulated information and add it to ' the XML. OutputResult("Basic model info", info, xContainer, errorsContainer)
Principais tipos e membros aqui incluem o seguinte: DataSchemaModel, ModelStore, DatabaseSchemaProvider, and ModelCollation.
Para adicionar o corpo do método de resumir
Adicione o seguinte código ao corpo do método resumir:
// Use a Dictionary to keep all summarized information var statistics = new Dictionary<string, int>(); // For each element in the provided list, // count items based on the specified grouping var groups = from item in set group item by groupValue(item) into g select new { g.Key, Count = g.Count() }; // order the groups as requested by the user if (this._sortBy == SortBy.Name) { groups = groups.OrderBy(group => group.Key); } else if (this._sortBy == SortBy.Value) { groups = groups.OrderBy(group => group.Count); } // build the Dictionary of accumulated statistics // that will be passed along to the OutputResult method. foreach (var item in groups) { statistics.Add(item.Key, item.Count); } statistics.Add("subtotal", set.Count); statistics.Add("total items", groups.Count()); // output the results, and build up the XML OutputResult(category, statistics, xContainer, errorsContainer);
' Use a Dictionary to keep all summarized information Dim statistics = New Dictionary(Of String, Integer)() ' For each element in the provided list, ' count items based on the specified grouping Dim groups = From item In [set] _ Group item By groupValue(item)Intog _ Select New () ' order the groups as requested by the user If Me._sortBy = SortBy.Name Then groups = groups.OrderBy(Function(group) group.Key) ElseIf Me._sortBy = SortBy.Value Then groups = groups.OrderBy(Function(group) group.Count) End If ' build the Dictionary of accumulated statistics ' that will be passed along to the OutputResult method. For Each item In groups statistics.Add(item.Key, item.Count) Next statistics.Add("subtotal", [set].Count) statistics.Add("total items", groups.Count()) ' output the results, and build up the XML OutputResult(category, statistics, xContainer, errorsContainer)
Novamente, os comentários de código fornecem as informações relevantes.
Para adicionar o corpo do método SurveyRelationships
Adicione o seguinte código ao corpo do método SurveyRelationships:
// get a list that contains all elements in the model var elements = model.GetElements(typeof(IModelElement), ModelElementQueryFilter.All); // We are interested in all relationships that // reference each element. var entries = from element in elements from entry in element.GetReferencedRelationshipEntries() select entry; // initialize our counting buckets var single = 0; var many = 0; var composing = 0; var hierachical = 0; var peer = 0; var reverse = 0; // process each relationship, adding to the // appropriate bucket for style and type. foreach (var entry in entries) { switch (entry.RelationshipClass.ModelRelationshipCardinalityStyle) { case ModelRelationshipCardinalityStyle.Many: ++many; break; case ModelRelationshipCardinalityStyle.Single: ++single; break; default: break; } switch (entry.RelationshipClass.ModelRelationshipType) { case ModelRelationshipType.Composing: ++composing; break; case ModelRelationshipType.Hierarchical: ++hierachical; break; case ModelRelationshipType.Peer: ++peer; break; case ModelRelationshipType.Reverse: // We count these, but reverse relationships // are not actually stored*, so the count // will always be zero. // * - reverse relationships are generated // dynamically when they are accessed. ++reverse; break; default: break; } } // build a dictionary of data to pass along // to the OutputResult method. var stat = new Dictionary<string, int>(); stat.Add("Multiple", many); stat.Add("Single", single); stat.Add("Composing", composing); stat.Add("Hierarchical", hierachical); stat.Add("Peer", peer); // As noted, no need to output the count of reverse // relationships as it will always be zero. //stat.Add("Reverse", reverse); stat.Add("subtotal", entries.Count()); OutputResult("Relationships", stat, xContainer, errorsContainer);
' get a list that contains all elements in the model Dim elements = model.GetElements(GetType(IModelElement), ModelElementQueryFilter.All) ' We are interested in all relationships that ' reference each element. Dim entries = From element In elements _ From entry In element.GetReferencedRelationshipEntries() _ Select entry ' initialize our counting buckets Dim [single] = 0 Dim many = 0 Dim composing = 0 Dim hierachical = 0 Dim peer = 0 Dim reverse = 0 ' process each relationship, adding to the ' appropriate bucket for style and type. For Each entry In entries Select Case entry.RelationshipClass.ModelRelationshipCardinalityStyle Case ModelRelationshipCardinalityStyle.Many many += 1 Exit Select Case ModelRelationshipCardinalityStyle.[Single] [single] += 1 Exit Select Case Else Exit Select End Select Select Case entry.RelationshipClass.ModelRelationshipType Case ModelRelationshipType.Composing composing += 1 Exit Select Case ModelRelationshipType.Hierarchical hierachical += 1 Exit Select Case ModelRelationshipType.Peer peer += 1 Exit Select Case ModelRelationshipType.Reverse ' We count these, but reverse relationships ' are not actually stored*, so the count ' will always be zero. ' * - reverse relationships are generated ' dynamically when they are accessed. reverse += 1 Exit Select Case Else Exit Select End Select Next ' build a dictionary of data to pass along ' to the OutputResult method. Dim stat = New Dictionary(Of String, Integer)() stat.Add("Multiple", many) stat.Add("Single", [single]) stat.Add("Composing", composing) stat.Add("Hierarchical", hierachical) stat.Add("Peer", peer) ' As noted, no need to output the count of reverse ' relationships as it will always be zero. 'stat.Add("Reverse", reverse); stat.Add("subtotal", entries.Count()) OutputResult("Relationships", stat, xContainer, errorsContainer)
Os comentários de código explicam os principais aspectos desse método. Tipos referenciados e métodos de anotação incluem o seguinte: DataSchemaModel, ModelStore, GetElements, and ModelElement.
Para adicionar o corpo do método OutputResult
Adicione o seguinte corpo para o método OutputResult:
var maxLen = statistics.Max(stat => stat.Key.Length) + 2; var format = string.Format("{{0, {0}}}: {{1}}", maxLen); List<DataSchemaError> args = new List<DataSchemaError>(); args.Add(new DataSchemaError(category, ErrorSeverity.Message)); args.Add(new DataSchemaError("-----------------", ErrorSeverity.Message)); // Remove any blank spaces from the category name var xCategory = new XElement(category.Replace(" ", "")); xContainer.Add(xCategory); foreach (var item in statistics) { //Console.WriteLine(format, item.Key, item.Value); var entry = string.Format(format, item.Key, item.Value); args.Add(new DataSchemaError(entry, ErrorSeverity.Message)); // Replace any blank spaces in the element key with // underscores. xCategory.Add(new XElement(item.Key.Replace(' ', '_'), item.Value)); } args.Add(new DataSchemaError(" ", ErrorSeverity.Message)); errorsContainer.Add(args, ErrorManager.BuildCategory);
Dim maxLen = statistics.Max(Function(stat) stat.Key.Length) + 2 Dim format = String.Format("{{0, {0}}}: {{1}}", maxLen) Dim args As New List(Of DataSchemaError)() args.Add(New DataSchemaError(category, ErrorSeverity.Message)) args.Add(New DataSchemaError("-----------------", ErrorSeverity.Message)) ' Remove any blank spaces from the category name Dim xCategory = New XElement(category.Replace(" ", "")) xContainer.Add(xCategory) For Each item In statistics 'Console.WriteLine(format, item.Key, item.Value); Dim entry = String.Format(format, item.Key, item.Value) args.Add(New DataSchemaError(entry, ErrorSeverity.Message)) ' Replace any blank spaces in the element key with ' underscores. xCategory.Add(New XElement(item.Key.Replace(" "c, "_"c), item.Value)) Next args.Add(New DataSchemaError(" ", ErrorSeverity.Message)) errorsContainer.Add(args, ErrorManager.BuildCategory)
Salve as alterações Class1. cs.
Em seguida, você pode criar a biblioteca de classes.
Para assinar e compilar o assembly
Sobre o projeto menu, clique em Propriedades de MyBuildContributor.
Clique na guia Signing.
Clique em Sign the assembly.
Em Choose a strong name key file, clique em <New>.
No Create Strong Name Key na caixa nome do arquivo de chave, tipo MyRefKey.
(opcional) Você pode especificar uma senha para seu arquivo de chave de nome forte.
Clique em OK.
No menu File, clique em Save All.
Sobre o Build menu, clique em Build Solution.
Em seguida, você deve instalar e registrar o assembly para que ele será carregado quando você constrói os projetos de banco de dados.
Instalar um colaborador de compilação
Para instalar um colaborador de compilação, você deve executar as seguintes tarefas:
Copie o assembly e o arquivo. PDB de associados para a pasta de extensões
Criar um arquivo de Extensions.xml para registrar o colaborador de compilação para que ele é carregado quando você constrói os projetos de banco de dados
Para instalar o conjunto de MyBuildContributor
Crie uma pasta chamada MyExtensions na pasta % do programa Files%\Microsoft Visual Studio 10.0\VSTSDB\Extensions.
Copie o assembly assinado (MyBuildContributor.dll) para a pasta de 10.0\VSTSDB\Extensions\MyExtensions de Visual Studio do programa Files%\Microsoft %.
Observação Recomendamos não copie os arquivos XML diretamente para a pasta de 10.0\VSTSDB\Extensions de Visual Studio do programa Files%\Microsoft %. Se você usar uma subpasta em vez disso, você evitará que alterações acidentais feitas para os arquivos que são fornecidos com Visual Studio Premium.
Em seguida, você deve registrar seu assembly, um tipo de a extensão de recurso, de modo que ele aparecerá na Visual Studio Premium.
Para registrar o assembly de MyBuildContributor
No Exibir menu, clique em Other Windowse em seguida, clique em Janela de comando para abrir o comando janela.
No comando janela, digite o seguinte código. Para FilePath, substitua o caminho e o nome do arquivo. dll de compilado. Inclua as aspas ao redor do caminho e nome de arquivo.
Observação Por padrão, o caminho do seu arquivo compilado. dll é YourSolutionPath\bin\Debug ou YourSolutionPath\bin\Release.
? System.Reflection.Assembly.LoadFrom("FilePath").FullName
? System.Reflection.Assembly.LoadFrom(@"FilePath").FullName
Pressione Digite.
Copie a linha resultante para a área de transferência. A linha deve ser semelhante ao seguinte:
"MyBuildContributor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=nnnnnnnnnnnnnnnn"
Abra um editor de texto sem formatação, como, por exemplo, o bloco de notas.
Importante Em Windows Vista e a Microsoft Windows Server 2008, abra o editor como um administrador para que você pode salvar o arquivo em sua pasta de arquivos de programa.
Forneça as informações a seguintes. Você pode colar as informações que você copiou na etapa 4. Especifique seu próprio nome de assembly, o token de chave pública e o tipo de extensão:
<?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="MyBuildContributor.ModelStatistics" assembly="MyBuildContributor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=<enter key here>" enabled="true" /> </extensions>
Você usa este arquivo XML para registrar a classe que herda de BuildContributor .
Salve o arquivo como MyBuildContributor.extensions.xml na pasta % do programa Files%\Microsoft Visual Studio 10.0\VSTSDB\Extensions\MyExtensions.
Observação Em Salvar como tipo, verifique se você especificou Todos os arquivos, ou o bloco de notas irá ignorar a extensão e salvar os arquivos com a extensão. txt.
Close Visual Studio.
Em seguida, você criará um projeto de banco de dados para testar seu colaborador.
Teste seu colaborador de compilação
Para testar seu colaborador de compilação, você deve executar as seguintes tarefas:
Adicionar propriedades para o arquivo de .dbproj que você planeja construir
Construir o projeto de banco de dados usando o MSBuild e fornecendo os parâmetros apropriados
Adicionar propriedades para o projeto de banco de dados (.dbproj) o arquivo
Porque este Colaborador de compilação aceita parâmetros de linha de comando do MSBuild, você deve modificar o projeto de banco de dados para permitir aos usuários passar esses parâmetros por meio de MSBuild. Você pode fazer isso de duas maneiras. Você pode modificar manualmente o arquivo .dbproj para adicionar os argumentos necessários. Você pode optar por fazer isso, se você apenas construir seu projeto de banco de dados usando MSBuild. Se você escolher esta opção, adicione as seguintes instruções para o arquivo de .dbproj entre o último </ItemGroup> o nó no arquivo e o final </Project> nó:
<ItemGroup>
<BuildContributorArgument Include="OutDir=$(OutDir)" />
<BuildContributorArgument Include="GenerateModelStatistics=$(GenerateModelStatistics)" />
<BuildContributorArgument Include="SortModelStatisticsBy=$(SortModelStatisticsBy)" />
</ItemGroup>
O método mais fácil é carregar seu projeto de banco de dados em Visual Studio Construir o projeto de banco de dados de uma vez, e depois sair Visual Studio. Salvar alterações em seu projeto quando você sair. Se você usar esse método, os argumentos adicionais são adicionados automaticamente ao seu arquivo de projeto de banco de dados (.dbproj).
Depois de ter seguido de uma dessas abordagens, você pode usar MSBuild passar os parâmetros para compilações de linha de comando.
Para adicionar propriedades ao arquivo de banco de dados do projeto
Abra o projeto de banco de dados no Visual Studio. Para obter mais informações, consulte Como: Abrir um banco de dados ou projeto do servidor.
Crie seu projeto de banco de dados. Para obter mais informações, consulte Como: Construir um projeto de banco de dados para gerar um esquema compilado (.dbschema) o arquivo.
Fechar Visual Studio. Salve sua solução e projeto se você for solicitado para fazer o SO.
Em seguida, você pode criar seu projeto de banco de dados usando o MSBuild e especificar argumentos para permitir que o colaborador de compilação gerar estatísticas de modelo.
Construir o projeto de banco de dados
Para reconstruir seu projeto de banco de dados usando o MSBuild e gerar estatísticas
Abrir um Visual Studio o Prompt de comando. No Iniciar menu, clique em Todos os programas, clique em 2010 do Microsoft Visual Studio, clique em Visual Studio Toolse clique em Prompt de comando Visual Studio (2010).
No prompt de comando, navegue até a pasta que contém o seu projeto de banco de dados.
No prompt de comando, digite a seguinte linha de comando:
MSBuild /t:Rebuild MyDatabaseProject.dbproj /p:GenerateModelStatistics=true /p:SortModelStatisticsBy=name /p:OutDir=.\
Substitua MyDatabaseProject com o nome do projeto de banco de dados que você deseja criar. Se você alterou o projeto após a última compilação, você poderia usar /t:Build em vez de /t: Rebuild.
Será exibida uma saída como o seguinte:
Microsoft (R) Build Engine Version 4.0.20817.0
[Microsoft .NET Framework, Version 4.0.20817.0]
Copyright (C) Microsoft Corporation 2007. All rights reserved.
Build started 8/19/2009 2:46:04 PM.
Project "C:\Users\UserName\Documents\Visual Studio 2010\Projects\MyDatabaseProject\MyDatabaseProject\MyDatabaseProject.dbproj" on node 1 (Rebuild target(s)).
CoreClean:
Deleting file "c:\users\UserName\documents\visual studio 2010\Projects\MyDatabaseProject\MyDatabaseProject\sql\debug\MyDatabaseProject_Script.PreDeployment.sql".
Deleting file "c:\users\UserName\documents\visual studio 2010\Projects\MyDatabaseProject\MyDatabaseProject\sql\debug\MyDatabaseProject_Script.PostDeployment.sql".
Deleting file "c:\users\UserName\documents\visual studio 2010\Projects\MyDatabaseProject\MyDatabaseProject\sql\debug\MyDatabaseProject_Database.sqlsettings".
Deleting file "c:\users\UserName\documents\visual studio 2010\Projects\MyDatabaseProject\MyDatabaseProject\sql\debug\MyDatabaseProject_Database.sqldeployment".
Deleting file "c:\users\UserName\documents\visual studio 2010\Projects\MyDatabaseProject\MyDatabaseProject\sql\debug\MyDatabaseProject_Database.sqlcmdvars".
Deleting file "c:\users\UserName\documents\visual studio 2010\Projects\MyDatabaseProject\MyDatabaseProject\sql\debug\MyDatabaseProject.deploymanifest".
Deleting file "c:\users\UserName\documents\visual studio 2010\Projects\MyDatabaseProject\MyDatabaseProject\sql\debug\MyDatabaseProject.dbschema".
Deleting file "c:\users\UserName\documents\visual studio 2010\Projects\MyDatabaseProject\MyDatabaseProject\obj\Debug\MyDatabaseProject.dbschema".
DspBuild:
Creating a model to represent the project...
Loading project files...
Building the project model and resolving object interdependencies...
Validating the project model...
Model Statistics:
=================
Basic model info
-----------------
DSP: Sql100DatabaseSchemaProvider
Collation: 1033(CI)
Internal Elements
-----------------
ISql100DatabaseOptions: 1
ISql100Filegroup: 1
ISql100FullTextIndex: 3
ISql100Index: 95
ISql100MultiStatementTableValuedFunction: 1
ISql100PrimaryKeyConstraint: 71
ISql100Procedure: 10
ISql100ScalarFunction: 10
ISql100SimpleColumn: 481
ISql100SubroutineParameter: 41
ISql100Table: 71
ISql100UniqueConstraint: 1
ISql100View: 20
ISql100XmlIndex: 8
ISql90CheckConstraint: 89
ISql90ComputedColumn: 302
ISql90DatabaseDdlTrigger: 1
ISql90DefaultConstraint: 152
ISql90DmlTrigger: 10
ISql90File: 3
ISql90ForeignKeyConstraint: 90
ISql90FullTextCatalog: 1
ISql90Route: 1
ISql90Schema: 5
ISql90TriggerEventTypeSpecifier: 125
ISql90TypeSpecifier: 524
ISql90UserDefinedDataType: 6
ISql90XmlSchemaCollection: 6
ISql90XmlTypeSpecifier: 8
ISqlDynamicColumnSource: 5
ISqlExtendedProperty: 1161
ISqlFullTextIndexColumnSpecifier: 4
ISqlIndexedColumnSpecification: 220
ISqlScriptFunctionImplementation: 11
subtotal: 3538
total items: 34
External Elements
-----------------
ISql100Filegroup: 1
ISql100Queue: 3
ISql100Service: 3
ISql90Assembly: 1
ISql90AssemblySource: 1
ISql90ClrMethod: 151
ISql90ClrMethodParameter: 138
ISql90ClrProperty: 16
ISql90Contract: 6
ISql90Endpoint: 5
ISql90MessageType: 14
ISql90Role: 10
ISql90Schema: 13
ISql90TypeSpecifier: 305
ISql90User: 4
ISql90UserDefinedDataType: 1
ISql90UserDefinedType: 3
ISqlBuiltInType: 32
ISqlServerRole: 9
subtotal: 716
total items: 19
Relationships
-----------------
Multiple: 3002
Single: 4017
Composing: 2332
Hierarchical: 1812
Peer: 2875
subtotal: 7019
Annotations
-----------------
ExternalPropertyAnnotation: 1475
ExternalReferenceAnnotation: 187
ExternalSourceAnnotation: 2
ModuleInvocationAnnotation: 20
ParameterOrVariableAnnotation: 68
ResolveTimeVerifiedDanglingRelationshipAnnotation: 119
SqlInlineConstraintAnnotation: 1
SqlModelBuilderResolvableAnnotation: 7825
SysCommentsObjectAnnotation: 52
subtotal: 9749
total items: 9
Custom Data
-----------------
AnsiNulls: 1
ClrTypesDbSchema: 1
CompatibilityMode: 1
ModelCapability: 1
Permissions: 1
QuotedIdentifier: 1
subtotal: 6
total items: 6
Result was saved to .\ModelStatistics.xml
Writing model to MyDatabaseProject.dbschema...
CopyFilesToOutputDirectory:
Copying file from "obj\Debug\MyDatabaseProject.dbschema" to ".\sql\debug\MyDatabaseProject.dbschema".
MyDatabaseProject -> C:\Users\UserName\Documents\Visual Studio 2010\Projects\MyDatabaseProject\MyDatabaseProject\sql\debug\MyDatabaseProject.dbschema
Done Building Project "C:\Users\UserName\Documents\Visual Studio 2010\Projects\MyDatabaseProject\MyDatabaseProject\MyDatabaseProject.dbproj" (Rebuild target(s)).
Build succeeded.
0 Warning(s)
0 Error(s)
Time Elapsed 00:00:11.20
Abra ModelStatistics.xml e examine o conteúdo.
Os resultados que foram relatados também são mantidos no arquivo XML.
Próximas etapas
Você pode criar ferramentas adicionais para executar o processamento do arquivo XML de saída. Este é apenas um exemplo de um colaborador de compilação. Por exemplo, você criaria um colaborador de compilação para um arquivo de dicionário de dados de saída como parte de sua compilação.
Consulte também
Conceitos
Estender os recursos de banco de dados de Visual Studio