2009-10-29 3 views
3

Microsoft.Data.Schema.ScriptDom 및 Microsoft.Data.Schema.ScriptDom.Sql 인터페이스를 구현하는 기본 C# 클래스를 만들었습니다. 이 두 어셈블리는 VSDB (Visual Studio Database Edition)의 일부이며 구문 분석/스크립팅 API입니다. SQL 텍스트를 구문 분석하고 형식 SQL 스크립트를 출력 할 수 있습니다. VSDB 어셈블리에 대한 자세한 내용은 this blog post을 참조하십시오. 나는 실행시의 형태를 만들 수 PowerShell을 V2 추가 형을 사용하고Add-Type 오류 메타 파일을 찾을 수 없습니다.

#requires -version 2 

add-type -path .\Microsoft.Data.Schema.ScriptDom.dll 
add-type -path .\Microsoft.Data.Schema.ScriptDom.Sql.dll 

$Source = @" 
using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using Microsoft.Data.Schema.ScriptDom; 
using Microsoft.Data.Schema.ScriptDom.Sql; 
using System.IO; 

    public class SQLParser 
    { 
     private IScriptFragment fragment; 

     public SQLParser(SqlVersion sqlVersion, bool quotedIdentifier, string inputScript) 
     { 
      switch (sqlVersion) 
      { 
       case SqlVersion.Sql80: 
        SQLParser80 (quotedIdentifier, inputScript); 
        break; 
       case SqlVersion.Sql90: 
        SQLParser90 (quotedIdentifier, inputScript); 
        break; 
       case SqlVersion.Sql100: 
        SQLParser100 (quotedIdentifier, inputScript); 
        break; 
      } 
     } 

     private void SQLParser100 (bool quotedIdentifier, string inputScript) 
     { 
      TSql100Parser parser = new TSql100Parser(quotedIdentifier); 
      Parse(parser, inputScript); 
     } 

     private void SQLParser90 (bool quotedIdentifier, string inputScript) 
     { 
      TSql90Parser parser90 = new TSql90Parser(quotedIdentifier); 
      Parse(parser90, inputScript); 
     } 

     private void SQLParser80 (bool quotedIdentifier, string inputScript) 
     { 
      TSql80Parser parser80 = new TSql80Parser(quotedIdentifier); 
      Parse(parser80, inputScript); 
     } 

     private void Parse(TSql100Parser parser, string inputScript) 
     { 
      IList<ParseError> errors; 

      using (StringReader sr = new StringReader(inputScript)) 
      { 
       fragment = parser.Parse(sr, out errors); 
      } 

      if (errors != null && errors.Count > 0) 
      { 
       StringBuilder sb = new StringBuilder(); 
       foreach (var error in errors) 
       { 
        sb.AppendLine(error.Message); 
        sb.AppendLine("offset " + error.Offset.ToString()); 
       } 
       throw new ArgumentException("InvalidSQLScript", sb.ToString()); 
      } 
     } 

     private void Parse(TSql90Parser parser, string inputScript) 
     { 
      IList<ParseError> errors; 

      using (StringReader sr = new StringReader(inputScript)) 
      { 
       fragment = parser.Parse(sr, out errors); 
      } 

      if (errors != null && errors.Count > 0) 
      { 
       StringBuilder sb = new StringBuilder(); 
       foreach (var error in errors) 
       { 
        sb.AppendLine(error.Message); 
        sb.AppendLine("offset " + error.Offset.ToString()); 
       } 
       throw new ArgumentException("InvalidSQLScript", sb.ToString()); 
      } 
     } 

     private void Parse(TSql80Parser parser, string inputScript) 
     { 
      IList<ParseError> errors; 

      using (StringReader sr = new StringReader(inputScript)) 
      { 
       fragment = parser.Parse(sr, out errors); 
      } 

      if (errors != null && errors.Count > 0) 
      { 
       StringBuilder sb = new StringBuilder(); 
       foreach (var error in errors) 
       { 
        sb.AppendLine(error.Message); 
        sb.AppendLine("offset " + error.Offset.ToString()); 
       } 
       throw new ArgumentException("InvalidSQLScript", sb.ToString()); 
      } 
     } 

     public IScriptFragment Fragment 
     { 
      get { return fragment; } 
     } 


    } 
"@ 
$refs = @("Microsoft.Data.Schema.ScriptDom","Microsoft.Data.Schema.ScriptDom.Sql") 
add-type -ReferencedAssemblies $refs -TypeDefinition $Source -Language CSharpVersion3 -passThru 

: 그들은 재배포 때문에, 나는 어셈블리 및 PowerShell 스크립트 here 모두를 포함 시켰습니다. 나는 3 개의 다른 기계에 원본을 시험했다. 한 컴퓨터에서 스크립트는 다른 두 컴퓨터에서 예상대로 작동하여 다음 오류가 발생합니다. 참조 된 어셈블리는 모두 PowerShell 스크립트와 동일한 폴더에 저장됩니다. 내가 뭘 잘못하고 있는지에 대한 아이디어가 있습니까? 당신이 스크립트와 같은 디렉토리에 VSTSDB 어셈블리를 넣으면

PS C:\Users\u00\bin> .\SQLParser.ps1 
Add-Type : (0) : Metadata file 'Microsoft.Data.Schema.ScriptDom.dll' could not be found 
(1) : using System; 
At C:\Users\u00\bin\SQLParser.ps1:125 char:9 
+ add-type <<<< -ReferencedAssemblies $refs -TypeDefinition $Source -Language CSharpVersion3 -passThru 
    + CategoryInfo   : InvalidData: (error CS0006: M...ld not be found:CompilerError) [Add-Type], Exception 
    + FullyQualifiedErrorId : SOURCE_CODE_ERROR,Microsoft.PowerShell.Commands.AddTypeCommand 

Add-Type : (0) : Metadata file 'Microsoft.Data.Schema.ScriptDom.Sql.dll' could not be found 
(1) : using System; 
At C:\Users\u00\bin\SQLParser.ps1:125 char:9 
+ add-type <<<< -ReferencedAssemblies $refs -TypeDefinition $Source -Language CSharpVersion3 -passThru 
    + CategoryInfo   : InvalidData: (error CS0006: M...ld not be found:CompilerError) [Add-Type], Exception 
    + FullyQualifiedErrorId : SOURCE_CODE_ERROR,Microsoft.PowerShell.Commands.AddTypeCommand 

Add-Type : Cannot add type. There were compilation errors. 
At C:\Users\u00\bin\SQLParser.ps1:125 char:9 
+ add-type <<<< -ReferencedAssemblies $refs -TypeDefinition $Source -Language CSharpVersion3 -passThru 
    + CategoryInfo   : InvalidData: (:) [Add-Type], InvalidOperationException 
    + FullyQualifiedErrorId : COMPILER_ERRORS,Microsoft.PowerShell.Commands.AddTypeCommand 
+0

블로그 게시물 : //chadwickmiller.spaces.live.com/blog/cns!EA42395138308430!590.entry –

답변

6

아주 간단합니다, 당신은 그들이 이름으로 참조 할 수 있도록 그 어셈블리가 GAC에 있기 때문에 ;-)

맥스의 예를 작동 알면. 어셈블리가 없으므로 경로로 참조해야합니다.

당신은 적어도이 아닌 해당 스크립트를 들어, 하나 상단에 추가 형 참조를 필요가 없습니다 - 그냥이에 라인의 마지막 몇 변경 : SQLParser의 HTTP에 대한

$PSScriptRoot = (Split-Path $MyInvocation.MyCommand.Path -Parent) 
$refs = @("$PSScriptRoot\Microsoft.Data.Schema.ScriptDom.dll","$PSScriptRoot\Microsoft.Data.Schema.ScriptDom.Sql.dll") 
add-type -ReferencedAssemblies $refs -TypeDefinition $Source -Language CSharpVersion3 -passThru 
+0

OMG, 간단하고 작동합니다! 정말 고맙습니다. –

2

당신은 사용하지 않는다 "." 상대 경로. "." 스크립트가 호출되는 디렉토리에 상대적입니다. 대신 다음과 같이 시도해보십시오.

$ScriptDir = Split-Path $MyInvocation.MyCommand.Path -Parent 
Add-Type -Path "$ScriptDir\Microsoft.Data.Schema.ScriptDom.dll" 
+0

좋은 제안이지만, 나는 그것을 시도했다. 내가 나서서 다시 시도, 변경 한 후에 같은 오류 : $ ScriptDir = 분할 경로 ($의 MyInvocation.MyCommand.Path를) -parent -Path "$ ScriptDir \ Microsoft.Data.Schema.ScriptDom 형을 추가합니다. dll " Add-Type -Path"$ ScriptDir \ Microsoft.Data.Schema.ScriptDom.Sql.dll " 어셈블리가 현재 디렉터리에 있습니다. PS C : \ Users \ u00 \ bin> ls Microsoft.Data .Schema.ScriptDom * | 이름 이름 을 선택 ---- Microsoft.Data.Schema.ScriptDom.dll Microsoft.Data.Schema.ScriptDom.Sql.dll 코드를 컴파일 할 수 있습니까? –

+1

아니, 나는 데이터 Dude 판 VS가 없다. 또 다른 생각은로드가 실패하게 만드는 다른 어셈블리 (종속성)가있을 수 있습니까? fuslogvw.exe (Windows/.NET SDK)를 사용하여 CLR fusion로드 실패를 모니터 할 수 있습니다. –

+0

또한 두 개의 어셈블리를 ILDASM에로드하고 매니페스트를보고 다른 어셈블리가 종속되어 있는지 확인할 수 있습니다. –

1

나는 우리 PS 트랙에서 사용했던 샘플을 가지고 있습니다. 그것은 다소 기본이지만 작동합니다. SMO를 사용하는 코드는 다음과 같습니다.

$Assem = ("Microsoft.SqlServer.Smo","Microsoft.SqlServer.ConnectionInfo") 
$Source = @" 
public class MyMSSql 
{ 
     public static string getEdition(string sqlName) 
     { 
      string sqlEdition; 
      Microsoft.SqlServer.Management.Smo.Server sname = new Microsoft.SqlServer.Management.Smo.Server(sqlName); 
      sqlEdition = sname.Information.Edition; 
      return sqlEdition; 
     } 
     public string getSqlEdition(string sqlName) 
     { 
      string sqlEdition; 
      Microsoft.SqlServer.Management.Smo.Server sname = new Microsoft.SqlServer.Management.Smo.Server(sqlName); 
      sqlEdition = sname.Information.Edition; 
      return sqlEdition; 
     } 

} 
"@; 
Add-Type -ReferencedAssemblies $Assem -TypeDefinition $Source 
[MyMSSql]::getEdition("MAX-PCWIN1") 
#Developer Edition (64-bit) 

$MySQLobj = New-Object MyMSSql 
$MySQLobj.getSqlEdition("MAX-PCWIN1") 

희망 사항은 힌트를 줄 것입니다.

최대

+0

감사합니다. 예, 발표 할 때 거기에 있었고 게시 한 코드를 처음 만들었을 때 추가 유형의 예를보기 위해 데모를 다운로드했습니다. –

관련 문제