如何穿越dacpac
本文关键字:dacpac 穿越 何穿越 | 更新日期: 2023-09-27 18:25:41
我们希望将dbproj升级到sqlproj,以便将其指向新的SQL 2012数据库。我们现在有一个程序,它读取.dbschema xml文件来查找所有表和列,并从中检索信息。我们使用这些数据来构建我们自己的自定义类。
新的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);
}
}
}
}
}
}
}
}
我不知道我做这件事的方式是否正确,或者是否有更好/更容易的方法。我不知道该在谷歌搜索什么,也找不到任何例子。
我可以看到变量列有一个名为ContextObject的非公共成员,它是Microsoft.Data.Tools.Schema.Sql.SchemaModel.SqlSimpleColumn。如果我可以访问这个对象,那么我就可以从中提取我需要的所有信息。Table也有一个类似的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属性获取属性和元数据的值或
- 从零开始,以更简单的方式获取这些信息
我们需要获得信息,例如列类型、它是否可以为null以及列的规模和精度
因此,在查询模型时可以使用一组完全定义的元数据类。这比依赖Linq并需要测试每个属性的字符串名称更简单。有关示例,请参见表和列类。我已经更新了你的例子,展示了这些是如何使用的:
// 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);
}
我们找到的方法是使用Linq在对象类型中找到属性,然后使用GetProperty
方法获得值:
bool isNullable = (bool)column.GetProperty(column.ObjectType.Properties.Where(p => p.Name == "Nullable").First());
这仍然不是最好的选择,所以如果其他人有更好的答案,请发布。