2009-10-29 10 views
3

J'ai créé une classe C# de base qui implémente l'interface Microsoft.Data.Schema.ScriptDom et Microsoft.Data.Schema.ScriptDom.Sql. Ces deux assemblys font partie de Visual Studio Database Edition (VSDB) et sont les API de parsing/scripting. Vous pouvez analyser le texte SQL et générer un script SQL au format. Pour plus d'informations sur les assemblys VSDB, voir this blog post. Puisqu'ils sont redistribuable, j'ai inclus les deux ensembles et le script PowerShell here:Erreur d'ajout de type Meta File introuvable

#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 

J'utilise PowerShell V2 ajouter type pour créer un type d'exécution. J'ai testé le script sur 3 machines différentes. Sur une machine le script fonctionne comme prévu sur les deux autres machines l'erreur suivante est produite. Les deux assemblys référencés sont placés dans le même dossier que le script PowerShell. Des idées sur ce que je fais mal?

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

Blog post sur SQLParser http: //chadwickmiller.spaces.live.com/blog/cns!EA42395138308430!590.entry –

Répondre

6

Assez simple, une fois que vous connaissez ;-)

exemple de Max fonctionne parce que ces assemblées sont dans le GAC afin qu'ils puissent être référencés par leur nom. Vos assemblys ne le sont pas, ils doivent donc être référencés par leur chemin.

Vous n'avez pas besoin les références Add-type en haut soit, au moins, pas pour ce script - il suffit de changer vos dernières lignes à ceci:

$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, C'était simple et ça marche! Merci beaucoup. –

2

Si vous mettez les ensembles de VSTSDB dans le même répertoire que le script alors vous ne voulez pas utiliser « » dans un chemin relatif. "." sera relatif au répertoire où le script est appelé. Essayez plutôt quelque chose comme ceci:

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

Bonne suggestion, mais j'ai essayé ça. Je suis allé de l'avant et j'ai essayé à nouveau, même erreur après avoir fait la modification: $ ScriptDir = Chemin de Split ($ MyInvocation.MyCommand.Path) -Parent Add-Type -Path "$ ScriptDir \ Microsoft.Data.Schema.ScriptDom. dll » Ajouter -type -Path "$ scriptdir \ Microsoft.Data.Schema.ScriptDom.Sql.dll" Les assemblées sont dans mon répertoire courant: PS C: \ Users \ U00 \ bin> ls Microsoft.Data .Schema.ScriptDom * | sélectionnez le nom Nom ---- Microsoft.Data.Schema.ScriptDom.dll Microsoft.Data.Schema.ScriptDom.Sql.dll Êtes-vous en mesure de compiler le code? –

+1

Non, je n'ai pas l'édition Data Dude de VS. Une autre pensée, pourrait-il être qu'il existe un autre assemblage qui est nécessaire (une dépendance) qui provoque l'échec de chargement? Vous pouvez essayer fuslogvw.exe (Windows/.NET SDK) pour surveiller les échecs de chargement de fusion CLR. –

+0

Vous pouvez également charger ces deux assemblys dans ILDASM, consultez le manifeste pour voir d'autres assemblys dont ils dépendent. –

1

J'ai un échantillon que j'ai utilisé pendant notre piste PS. C'est un peu basique mais ça marche. Voici le code utilisant 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") 

Espérons que cela vous donnera un indice.

Max

+0

Merci - Oui, j'étais là lorsque vous m'avez présenté et j'ai téléchargé vos démos pour voir quelques exemples d'add-type lorsque j'ai créé le code que j'ai posté. –

Questions connexes