2013-08-01 70 views
11

我們正在將我們的dbproj升級到sqlproj,以便我們可以將其指向新的SQL 2012數據庫。我們目前有一個程序,它讀取.dbschema xml文件以查找所有表和列,並從中檢索信息。我們使用這些數據來構建我們自己的自定義類。如何遍歷dacpac

新的sqlproj文件現在生成一個dacpac,我們想要interrigate來獲取我們需要的數據。我寫了下面的嘗試和遍歷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.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 

基本上,我想請執行下列操作之一:

  1. 訪問ContextObject獲得Microsoft.Data.Tools.Schema.Sql .SchemaModel。*對象 或
  2. 從無到有獲得來自對象類型屬性 或
  3. 啓動性能和元數據的值有更簡單的方法來獲取這些信息出來

我們需要得到的信息進行,如列類型,howif它是空的,且規模和精度列

回答

1

,我們發現這樣做是利用找到的對象類型屬性的方式LINQ中,然後使用GetProperty方法來獲取值:

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

這仍然不覺得自己是最好的選擇,所以如果別人有更好的答案,請張貼。

4

因此,在查詢模型時可以使用完全定義的一組元數據類。這比依賴Linq更簡單,並且需要測試每個屬性的字符串名稱。示例見TableColumn類。我已經更新了您的示例,其中顯示瞭如何使用這些內容:

// 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); 
    } 
+0

這非常有幫助。不幸的是,對於我來說,用戶定義的表類型似乎沒有相同的支持。例如model.GetObjects(DacQueryScopes.UserDefined,ModelSchema.TableType);試圖獲取SqlDataType不適用於這些,因爲類型「TableTypeColumn」不支持DataType。我會假設用戶定義表類型只會繼承普通的TableType。 – Davos

+1

嗨達沃斯,我們將Table和TableType元數據類視爲完全獨立,因此您需要對TableType使用不同的查詢。您應該可以使用GetReferenced(TableTypeColumn.DataType)來查找數據類型。當你注意到有兩個類型之間沒有繼承 - 從表-1>柱和TableType-整個關係棧> TableTypeColumn是不同的。 –

+0

再次感謝你,我想我現在弄明白了:) \t \t名單<組<字符串,字符串>> tvpcols = tvp.GetReferenced() \t \t \t \t \t \t \t \t \t \t \t。凡(C = > c.ObjectType.Name == 「TableTypeColumn」) \t \t \t \t \t \t \t \t \t \t \t。選擇(C => Tuple.Cre吃(c.Name.Parts.Last(),c.GetReferenced(TableTypeColumn.DataType)。去年()。的getProperty (DataType.SqlDataType)的ToString())) \t \t \t \t \t \t \t \t \t \t \t \t \t \t .ToList(); – Davos