Ho trovato l'assembly Microsoft.SqlServer.BatchParser nel GAC insieme al suo amico Microsoft.SqlServer.BatchParserClient che contiene le implementazioni dell'interfaccia IBatchSource.
namespace Microsoft.SqlServer.Management.Common
{
internal class BatchSourceFile : IBatchSource
internal class BatchSourceString : IBatchSource
}
Si è quindi verificata la seguente conversazione.
Assemblea: Ciao! Il mio nome è Microsoft.SqlServer.Management.Common.ExecuteBatch. Vorresti StringCollection GetStatements (stringa sqlCommand)?
Me: Sì, vorrei, assemblea BatchParserClient. Grazie per averlo chiesto!
Istruzioni ripetibili (provate a casa!)
- Installare Microsoft SQL Server 2008 R2 Shared Management Objects
- Copia Microsoft.SqlServer.BatchParser.dll e Microsoft.SqlServer.BatchParserClient.dll dal GAC ad un cartella nella tua soluzione.
- Riferimento microsoft.sqlserver.batchparser & Microsoft.SqlServer.BatchParserClient
Program.cs
using System;
using System.Collections.Specialized;
using System.IO;
using System.Text;
using Microsoft.SqlServer.Management.Common;
namespace ScriptParser
{
class Program
{
static void Main(string[] args)
{
ExecuteBatch batcher = new ExecuteBatch();
string text = File.ReadAllText(@"Path_To_My_Long_Sql_File.sql");
StringCollection statements = batcher.GetStatements(text);
foreach (string statement in statements)
{
Console.WriteLine(statement);
}
}
}
}
app.config
<?xml version="1.0"?>
<configuration>
<startup useLegacyV2RuntimeActivationPolicy="true">
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/>
</startup>
</configuration>
Un'altra opzione è quella di utilizzare ScriptDom come descritto in questa risposta: https://stackoverflow.com/a/32529415/26877.
using System;
using System.Collections.Generic;
using System.IO;
using Microsoft.SqlServer.TransactSql.ScriptDom;
namespace ScriptDomDemo
{
class Program
{
static void Main(string[] args)
{
TSql120Parser parser = new TSql120Parser(false);
IList<ParseError> errors;
using (StringReader sr = new StringReader(@"create table t1 (c1 int primary key)
GO
create table t2 (c1 int primary key)"))
{
TSqlFragment fragment = parser.Parse(sr, out errors);
IEnumerable<string> batches = GetBatches(fragment);
foreach (var batch in batches)
{
Console.WriteLine(batch);
}
}
}
private static IEnumerable<string> GetBatches(TSqlFragment fragment)
{
Sql120ScriptGenerator sg = new Sql120ScriptGenerator();
TSqlScript script = fragment as TSqlScript;
if (script != null)
{
foreach (var batch in script.Batches)
{
yield return ScriptFragment(sg, batch);
}
}
else
{
// TSqlFragment is a TSqlBatch or a TSqlStatement
yield return ScriptFragment(sg, fragment);
}
}
private static string ScriptFragment(SqlScriptGenerator sg, TSqlFragment fragment)
{
string resultString;
sg.GenerateScript(fragment, out resultString);
return resultString;
}
}
}
Siamo spiacenti, ma 'File.ReadAllText' continuerà a leggere l'intero file in memoria prima. Quindi con file di grandi dimensioni (forse irragionevolmente grandi, ma comunque), hai problemi. Fondamentalmente, sarebbe necessaria un'interfaccia "streaming". Come ho notato [qui sopra] (http://stackoverflow.com/a/12154400/21567), 'SQLCMD.EXE' è in grado di farlo, e presumibilmente usa anche' IBatchSource', anche se l'implementazione nativa e non il wrapper "gestito". La domanda rimane: come dividere il testo di input in blocchi in modo che BatchParser possa capirlo. (+1 anche se ancora, per un buon contributo) –
@ Christian.K trovato risposta https: // stackoverflow.it/a/32529415/26877 che potrebbe essere un'opzione per analizzare i tuoi batch usando ScriptDOM. – JJS