Как пройти через dacpac

Мы хотим обновить наш dbproj до sqlproj, чтобы мы могли указать его на новую базу данных SQL 2012. На данный момент у нас есть программа, которая читает XML файл .dbschema для поиска всех таблиц и столбцов и получения от них информации. Мы используем эти данные для создания собственных пользовательских классов.

Новый файл sqlproj теперь создает dacpac, который мы хотим, чтобы вырезать нужные нам данные. Я написал следующее, чтобы попытаться пройти dacpac и получить необходимую информацию:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.SqlServer.Dac;
using Microsoft.SqlServer.Dac.Extensions;
using Microsoft.SqlServer.Dac.Model;
namespace DacPacReader
{
    class Program
    {
        static void Main(string[] args)
        {
            using (System.IO.TextWriter writter = new System.IO.StreamWriter(@"c:\temp\output.txt"))
            {
                using (TSqlModel model = new TSqlModel(@"C:\temp\Data.dacpac"))
                {
                    var allTables = model.GetObjects(DacQueryScopes.All, ModelSchema.Table);

                    foreach (var table in allTables)
                    {
                        writter.WriteLine(table.Name);
                        foreach (var column in table.GetChildren().Where(child => child.ObjectType.Name == "Column"))
                        {
                            writter.WriteLine("\t" + column.Name);
                            writter.WriteLine("\tProperties:");
                            foreach (var property in column.ObjectType.Properties)
                            {
                                writter.WriteLine("\t\t" + property.Name + "\t\t" + property.DataType.FullName);
                            }
                            writter.WriteLine("\tMetadata:");
                            foreach (var metaData in column.ObjectType.Metadata)
                            {
                                writter.WriteLine("\t\t" + metaData.Name + "\t\t" + metaData.DataType.FullName);
                            }
                        }
                    }
                }
            }
        }
    }
}

Я понятия не имею, правильно ли я делаю это, или если есть намного лучший/более простой способ. Я не уверен, что искать в Google/S.E. и не может найти никаких примеров.

Я вижу, что столбец переменной имеет непубличный элемент, называемый ContextObject, который является Microsoft.Data.Tools.Schema.SchemaModel.SqlSimpleColumn. Если бы я мог получить доступ к этому объекту, тогда я смог бы вытащить всю необходимую мне информацию. Таблица также имеет аналогичный ContextObject, который бы мне помог.

В любом случае, в настоящее время это открывает dacpac и извлекает все имена таблиц и столбцов. Примером данных, которые я получаю, является:

[dbo].[User]
    [dbo].[User].[UserID]
    Properties:
        Collation       System.String
        IsIdentityNotForReplication     System.Boolean
        Nullable        System.Boolean
        IsRowGuidCol        System.Boolean
        Sparse      System.Boolean
        Expression      Microsoft.Data.Tools.Schema.Sql.SchemaModel.SqlScriptProperty
        Persisted       System.Boolean
        PersistedNullable       System.Nullable`1[[System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]
        Scale       System.Int32
        Precision       System.Int32
        Length      System.Int32
        IsMax       System.Boolean
        XmlStyle        Microsoft.SqlServer.Dac.Model.XmlStyle
        IdentityIncrement       System.String
        IdentitySeed        System.String
        IsFileStream        System.Boolean
        IsIdentity      System.Boolean
    Metadata:
        ColumnType      Microsoft.SqlServer.Dac.Model.ColumnType

В принципе, я хотел бы сделать одно из следующего:

  • Доступ к объекту ContextObject для получения объекта Microsoft.Data.Tools.Schema.Sql.SchemaModel. * ИЛИ
  • Получить значение свойства и метаданных из свойств ObjectType ИЛИ
  • Начните с нуля с более легкого способа получить эту информацию.

Нам нужно получить информацию, такую ​​как тип столбца, если она равна нулю, а масштаб и точность столбца

Ответ 1

Способ, которым мы это нашли, - найти свойство в типе объекта с использованием Linq, а затем с помощью метода GetProperty получить значение:

bool isNullable = (bool)column.GetProperty(column.ObjectType.Properties.Where(p => p.Name == "Nullable").First());

Это все еще не похоже на лучший вариант, поэтому, если у кого-то есть лучший ответ, отправьте его.

Ответ 2

Итак, существует полностью определенный набор классов метаданных, которые можно использовать при запросе модели. Это проще, чем полагаться на Linq и нужно проверить имена строк каждого свойства. См. Table и Column для примера. Я обновил ваш пример, показывая, как они используются:

// Query for UserDefined objects to just filter to your own objects. All will
// include system objects (references to objects in master.dacpac if you reference that
// and BuiltIn objects such as the data types. You probably don't care about those
var allTables = model.GetObjects(DacQueryScopes.UserDefined, Table.TypeClass);

foreach (var table in allTables)
{
    writter.WriteLine(table.Name);
    // Columns are referenced by tables, so GetReferenced can be used. The GetChildren can also be used 
    // but filtering by comparing "child.ObjectType == Column.TypeClass" would simplify your example
    foreach (var column in table.GetReferenced(Table.Columns))
    {
        // Now you can use the Column metadata class properties to query your Column object
        bool isNullable = column.GetProperty<bool>(Column.Nullable); 
        SqlDataType sdt = column.GetReferenced(Column.DataType).First().GetProperty<SqlDataType>(DataType.SqlDataType);
    }