简体   繁体   English

如何穿越dacpac

[英]How to traverse a dacpac

We are looking to upgrade our dbproj to a sqlproj so that we can point it to a new SQL 2012 database. 我们希望将dbproj升级到sqlproj,以便我们可以将它指向新的SQL 2012数据库。 We have a program at the moment that reads the .dbschema xml file to find all tables and columns and retrieve information from them. 我们现在有一个程序读取.dbschema xml文件以查找所有表和列并从中检索信息。 We use this data to build our own custom classes. 我们使用这些数据来构建我们自己的自定义类。

The new sqlproj file now produces a dacpac which we want to interrigate to get out the data that we need. 新的sqlproj文件现在生成一个dacpac,我们想要进行干预以获取我们需要的数据。 I have written the following to try and traverse the dacpac and get the information that I need: 我写了以下内容来尝试遍历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);
                            }
                        }
                    }
                }
            }
        }
    }
}

I have no idea if I'm doing this the right way, or if there is a much better/easier way. 我不知道我是以正确的方式做这件事,还是有更好/更容易的方式。 I'm not sure what to search for on Google/SE and can't find any examples. 我不确定在Google / SE上搜索什么,也找不到任何示例。

I can see that the variable column has a non-public member called ContextObject which is a Microsoft.Data.Tools.Schema.Sql.SchemaModel.SqlSimpleColumn. 我可以看到变量列有一个名为ContextObject的非公共成员,它是一个Microsoft.Data.Tools.Schema.Sql.SchemaModel.SqlSimpleColumn。 If I could access this object then I would be able to pull all the info I needed out of it. 如果我可以访问此对象,那么我将能够从中获取所需的所有信息。 Table also has a similar ContextObject which would help me. 表也​​有一个类似的ContextObject,它可以帮助我。

Anyway, currently this opens the dacpac and retrieves all of the table and column names. 无论如何,目前这将打开dacpac并检索所有表名和列名。 An example of the data I get is: 我得到的数据的一个例子是:

[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

Basically, I'd like to do one of the following: 基本上,我想做以下其中一项:

  1. Access the ContextObject to get a Microsoft.Data.Tools.Schema.Sql.SchemaModel.* object OR 访问ContextObject以获取Microsoft.Data.Tools.Schema.Sql.SchemaModel。*对象OR
  2. Get the value of the property and metadata from the ObjectType properties OR 从ObjectType属性OR获取属性和元数据的值
  3. Start from scratch with an easier way to get this information out 从头开始,以更简单的方式获取此信息

We need to get information out such as the column type, howif it's nullable, and the scale and precision of a column 我们需要获取信息,例如列类型,它是否可以为空,以及列的比例和精度

So, there is a fully-defined set of metadata classes that you can use when querying the model. 因此,在查询模型时可以使用一组完全定义的元数据类。 This is simpler than relying on Linq and needing to test the string names of each property. 这比依赖Linq并且需要测试每个属性的字符串名称更简单。 See Table and Column classes for an example. 有关示例,请参阅类。 I've updated your example showing how these are used: 我已经更新了您的示例,说明了如何使用它们:

// 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's properties to query your Column object
        bool isNullable = column.GetProperty<bool>(Column.Nullable); 
        SqlDataType sdt = column.GetReferenced(Column.DataType).First().GetProperty<SqlDataType>(DataType.SqlDataType);
    }

The way that we have found to do it is to find the property in object type using Linq, and then using the GetProperty method to get the value: 我们发现这样做的方法是使用Linq在对象类型中找到属性,然后使用GetProperty方法获取值:

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

This still doesn't feel like the best option, so if someone else has a better answer please post it. 这仍然不是最好的选择,所以如果其他人有更好的答案,请发布。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM