如何从 Visual Studio 扩展中获取对 SSDT 数据库项目内存模型的引用?
How to get reference to SSDT Database Project memory model from a Visual Studio Extension?
我正在尝试为 Visual Studio 2013 编写一个简单的扩展,它应该能够列出扩展用户选择的 SQL 服务器数据库项目中的所有表。为此,我需要访问数据库项目的内存模型。但我发现的唯一方法是将 DB 项目生成的已编译 .dacpac 文件加载到新的 TSqlModel 实例并查询它,但我宁愿能够使用 "live" 内存表示。我找到了 SSDT API 的教程:http://blogs.msdn.com/b/ssdt/archive/2013/12/23/dacfx-public-model-tutorial.aspx,但没有示例如何连接到 Visual Studio 中的内存模型。我还找到了一个解决此问题的教程,方法是从当前解决方案中收集所有带有 .sql 扩展名的文件并将它们的内容添加到 TSqlModel 实例中,但这不是我喜欢的方式。
这种事可能吗?如果可以,该怎么做?
谢谢,
米甲
数据库项目目前不提供可以访问模型的 Visual Studio 服务。但是,您可以通过挂接到项目系统事件并使用 API 来拥有自己的模型来模拟这一点。 Dave Ballantyne 在 this blog post 中展示了执行此操作的静态方法。如果您想让它更具动态性,您可以连接到项目事件,例如 project/file 添加、删除、更改等,并根据这些事件更新您的模型。这就是数据库项目内部发生的事情。请注意,您还应该使用 AddOrUpdateObjects API 调用而不是他使用的调用,因为这允许您在文件更改时更新它:
public void ProcessProjectModels()
{
var hostServiceProvider = (IServiceProvider)this.Host;
var dte = (DTE)hostServiceProvider.GetService(typeof(DTE));
using (TSqlModel model = new TSqlModel(SqlServerVersion.Sql110, new TSqlModelOptions { }))
{
foreach (Project project in dte.Solution)
{
IterateThroughProject(project.ProjectItems, model);
}
List<TSqlObject> allTables = GetAllTables(model);
foreach (var table in allTables)
{
// Do processing
}
}
}
public List<TSqlObject> GetAllTables(TSqlModel model)
{
List<TSqlObject> allTables = new List<TSqlObject>();
var tables = model.GetObjects(DacQueryScopes.All, ModelSchema.Table);
if (tables != null)
{
allTables.AddRange(tables);
}
return allTables;
}
private void IterateThroughProject(ProjectItems PrjItems, TSqlModel model)
{
foreach (ProjectItem PrjItem in PrjItems)
{
if (PrjItem.ProjectItems != null)
{
IterateThroughProject(PrjItem.ProjectItems, model);
}
if (//PrjItem.Object.GetType().ToString() == "Microsoft.VisualStudio.Data.Tools.Package.Project.DatabaseFileNode" &&
PrjItem.Name.EndsWith(".sql", StringComparison.OrdinalIgnoreCase))
{
// This is a sql file and will be processed
// Note: There should be a separate API to read the live contents of this item, to avoid the need to save it
if (!PrjItem.Saved)
{
PrjItem.Save();
}
StreamReader Reader = new StreamReader(PrjItem.FileNames[0]);
string Script = Reader.ReadToEnd();
model.AddOrUpdateObjects(Script, PrjItem.Name, null);
}
}
}
注意:此功能没有内置支持的原因是,要正确执行此操作,项目应提供只读模型(无法 add/update 脚本)或确保 add/update 对象调用实际上影响了项目中的相关脚本文件。如果您要对更改事件进行处理(就像项目系统支持的那样),它还应该支持事件通知。如果这对您有用(我可以想象在这种情况下会如此),那么打开一个 Connect 错误或在 Visual Studio 用户声音上提出它是让产品团队关注它的方法。
如何访问 SSDT 构建的项目内存模型。我们正在使用它来生成日志记录触发器。
先做 helper t4:
<#@ import namespace="Microsoft.SqlServer.Dac.Model" #>
<#@ assembly name="Microsoft.SqlServer.Dac.Extensions" #>
<#+
public TSqlModel GetModel()
{
return Model;
}
#>
主要 t4:
<#@ SqlModelDirective processor="SqlModelDirectiveProcessor" #>
<#@ import namespace="Microsoft.SqlServer.Dac.Model" #>
<#@ assembly name="Microsoft.SqlServer.Dac.Extensions" #>
<#@ include file="..\Helper.tt" #>
<#
blyablyablya
var allTables = GetAllTables();
blyablyablya
#>
<#+
// Example method.
public List<TSqlObject> GetAllTables()
{
List<TSqlObject> allTables = new List<TSqlObject>();
var model = GetModel();
if (model == null)
return allTables;
var tables = model.GetObjects(DacQueryScopes.All, ModelSchema.Table);
if (tables != null)
{
allTables.AddRange(tables);
}
return allTables;
}
#>
我正在尝试为 Visual Studio 2013 编写一个简单的扩展,它应该能够列出扩展用户选择的 SQL 服务器数据库项目中的所有表。为此,我需要访问数据库项目的内存模型。但我发现的唯一方法是将 DB 项目生成的已编译 .dacpac 文件加载到新的 TSqlModel 实例并查询它,但我宁愿能够使用 "live" 内存表示。我找到了 SSDT API 的教程:http://blogs.msdn.com/b/ssdt/archive/2013/12/23/dacfx-public-model-tutorial.aspx,但没有示例如何连接到 Visual Studio 中的内存模型。我还找到了一个解决此问题的教程,方法是从当前解决方案中收集所有带有 .sql 扩展名的文件并将它们的内容添加到 TSqlModel 实例中,但这不是我喜欢的方式。
这种事可能吗?如果可以,该怎么做?
谢谢, 米甲
数据库项目目前不提供可以访问模型的 Visual Studio 服务。但是,您可以通过挂接到项目系统事件并使用 API 来拥有自己的模型来模拟这一点。 Dave Ballantyne 在 this blog post 中展示了执行此操作的静态方法。如果您想让它更具动态性,您可以连接到项目事件,例如 project/file 添加、删除、更改等,并根据这些事件更新您的模型。这就是数据库项目内部发生的事情。请注意,您还应该使用 AddOrUpdateObjects API 调用而不是他使用的调用,因为这允许您在文件更改时更新它:
public void ProcessProjectModels()
{
var hostServiceProvider = (IServiceProvider)this.Host;
var dte = (DTE)hostServiceProvider.GetService(typeof(DTE));
using (TSqlModel model = new TSqlModel(SqlServerVersion.Sql110, new TSqlModelOptions { }))
{
foreach (Project project in dte.Solution)
{
IterateThroughProject(project.ProjectItems, model);
}
List<TSqlObject> allTables = GetAllTables(model);
foreach (var table in allTables)
{
// Do processing
}
}
}
public List<TSqlObject> GetAllTables(TSqlModel model)
{
List<TSqlObject> allTables = new List<TSqlObject>();
var tables = model.GetObjects(DacQueryScopes.All, ModelSchema.Table);
if (tables != null)
{
allTables.AddRange(tables);
}
return allTables;
}
private void IterateThroughProject(ProjectItems PrjItems, TSqlModel model)
{
foreach (ProjectItem PrjItem in PrjItems)
{
if (PrjItem.ProjectItems != null)
{
IterateThroughProject(PrjItem.ProjectItems, model);
}
if (//PrjItem.Object.GetType().ToString() == "Microsoft.VisualStudio.Data.Tools.Package.Project.DatabaseFileNode" &&
PrjItem.Name.EndsWith(".sql", StringComparison.OrdinalIgnoreCase))
{
// This is a sql file and will be processed
// Note: There should be a separate API to read the live contents of this item, to avoid the need to save it
if (!PrjItem.Saved)
{
PrjItem.Save();
}
StreamReader Reader = new StreamReader(PrjItem.FileNames[0]);
string Script = Reader.ReadToEnd();
model.AddOrUpdateObjects(Script, PrjItem.Name, null);
}
}
}
注意:此功能没有内置支持的原因是,要正确执行此操作,项目应提供只读模型(无法 add/update 脚本)或确保 add/update 对象调用实际上影响了项目中的相关脚本文件。如果您要对更改事件进行处理(就像项目系统支持的那样),它还应该支持事件通知。如果这对您有用(我可以想象在这种情况下会如此),那么打开一个 Connect 错误或在 Visual Studio 用户声音上提出它是让产品团队关注它的方法。
如何访问 SSDT 构建的项目内存模型。我们正在使用它来生成日志记录触发器。 先做 helper t4:
<#@ import namespace="Microsoft.SqlServer.Dac.Model" #>
<#@ assembly name="Microsoft.SqlServer.Dac.Extensions" #>
<#+
public TSqlModel GetModel()
{
return Model;
}
#>
主要 t4:
<#@ SqlModelDirective processor="SqlModelDirectiveProcessor" #>
<#@ import namespace="Microsoft.SqlServer.Dac.Model" #>
<#@ assembly name="Microsoft.SqlServer.Dac.Extensions" #>
<#@ include file="..\Helper.tt" #>
<#
blyablyablya
var allTables = GetAllTables();
blyablyablya
#>
<#+
// Example method.
public List<TSqlObject> GetAllTables()
{
List<TSqlObject> allTables = new List<TSqlObject>();
var model = GetModel();
if (model == null)
return allTables;
var tables = model.GetObjects(DacQueryScopes.All, ModelSchema.Table);
if (tables != null)
{
allTables.AddRange(tables);
}
return allTables;
}
#>