我正在尝试为Visual Studio 2013编写一个简单的扩展,它应该能够列出扩展用户选择的SQL Server数据库项目中的所有表。为此,我需要访问DB项目的内存模型。但我发现的唯一方法是将DB项目生成的已编译的.dacpac文件加载到新的TSqlModel实例并进行查询,但我宁愿能够使用“实时”内存表示。我已经找到了SSDT API的教程:http://blogs.msdn.com/b/ssdt/archive/2013/12/23/dacfx-public-model-tutorial.aspx,但是没有一个示例如何连接到Visual Studio中的内存模型。我还通过从当前解决方案中收集扩展名为.sql的所有文件并将其内容添加到TSqlModel实例中找到了解决此问题的教程,但这不是我喜欢的方式。
这样的事情有可能吗?如果是这样,怎么做?
谢谢你, 米甲
答案 0 :(得分:2)
数据库项目目前不提供可访问模型的Visual Studio服务。但是,您可以通过挂钩项目系统事件并使用API来拥有自己的模型来模拟这一点。 Dave Ballantyne在this blog post中展示了一种静态方法。如果您要使其更加动态,您可以连接项目事件,例如项目/文件添加,删除,更改等,并根据这些事件更新您的模型。这就是数据库项目内部发生的事情。请注意,您还应该使用AddOrUpdateObjects API调用而不是他使用的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);
}
}
}
注意:此功能没有内置支持的原因是,为了正确执行,项目应提供只读模型(无法添加/更新脚本)或确保添加/更新对象调用实际上会影响项目中的相关脚本文件。如果您要对更改事件进行处理(就像项目系统支持一样),它也应该支持事件通知。如果这对你有用(正如我可以想象的那样),那么打开Connect bug或者在Visual Studio用户语音上提高它就是在产品团队雷达上实现这一点的方法。
答案 1 :(得分:0)
如何访问SSDT构建的项目内存模型。我们正在使用它来生成日志记录触发器。 首先做助手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;
}
#>