usar que net executereader example ejecutar como comando c# sqlcommand sqlclient

que - sql command c# example



SqlCommand() ExecuteNonQuery() trunca el texto del comando (6)

Encontré el siguiente código mientras buscaba una respuesta a este problema:

http://blogs.msdn.com/b/onoj/archive/2008/02/26/incorrect-syntax-near-go-sqlcommand-executenonquery.aspx

Pros: Es breve y simple de entender y funcionó perfectamente para mis necesidades.

Contras: es menos eficiente que las soluciones basadas en Stream y distingue entre mayúsculas y minúsculas (es decir, "GO" no "go").

string[] commands = sql.Split(new string[]{"GO/r/n", "GO ", "GO/t"}, StringSplitOptions.RemoveEmptyEntries ); foreach (string c in commands) { var command = new SqlCommand(c, masterConnection); command.ExecuteNonQuery(); }

Estoy creando una utilidad de implementación de db personalizada, necesito leer archivos de texto que contengan scripts de SQL y ejecutarlos en la base de datos.

Cosas bastante fáciles, hasta ahora todo bien.

Sin embargo, he encontrado un obstáculo, el contenido del archivo se lee con éxito y en su totalidad, pero una vez que se pasa a SqlCommand y luego se ejecuta con SqlCommand.ExecuteNonQuery solo se ejecuta una parte del script.

Encendí Profiler y confirmé que mi código no está pasando todo el script.

private void ExecuteScript(string cmd, SqlConnection sqlConn, SqlTransaction trans) { SqlCommand sqlCmd = new SqlCommand(cmd, sqlConn, trans); sqlCmd.CommandType = CommandType.Text; sqlCmd.CommandTimeout = 9000000; // for testing sqlCmd.ExecuteNonQuery(); } // I call it like this, readDMLScript contains 543 lines of T-SQL string readDMLScript = ReadFile(dmlFile); ExecuteScript(readDMLScript, sqlConn, trans);


Esto es lo que usamos :)

public static class ExtensionMethodsSqlCommand { #region Public private static bool IsGo(string psCommandLine) { if (psCommandLine == null) return false; psCommandLine = psCommandLine.Trim(); if (string.Compare(psCommandLine, "GO", StringComparison.OrdinalIgnoreCase) == 0) return true; if (psCommandLine.StartsWith("GO", StringComparison.OrdinalIgnoreCase)) { psCommandLine = (psCommandLine + "--").Substring(2).Trim(); if (psCommandLine.StartsWith("--")) return true; } return false; } [System.Diagnostics.DebuggerHidden] public static void ExecuteNonQueryWithGos(this SqlCommand poSqlCommand) { string sCommandLong = poSqlCommand.CommandText; using (StringReader oStringReader = new StringReader(sCommandLong)) { string sCommandLine; string sCommandShort = string.Empty; while ((sCommandLine = oStringReader.ReadLine()) != null) if (ExtensionMethodsSqlCommand.IsGo(sCommandLine)) { if (sCommandShort.IsNullOrWhiteSpace() == false) { if ((poSqlCommand.Connection.State & ConnectionState.Open) == 0) poSqlCommand.Connection.Open(); using (SqlCommand oSqlCommand = new SqlCommand(sCommandShort, poSqlCommand.Connection)) oSqlCommand.ExecuteNonQuery(); } sCommandShort = string.Empty; } else sCommandShort += sCommandLine + "/r/n"; } } #endregion Public }



Respuesta basada en comentarios en la publicación original:

GO es un marcador para Management Studio / osql / isql. Le dice a enviar un lote de comandos a SQL Server. En su utilidad, debe dividir los datos de entrada usando GO como un delimitador y enviar cada elemento individualmente (sin el comando GO)


Sí, todos lo logran la primera vez que comienzan a enviar el contenido de los archivos de script SQL a la base de datos.

GO no es un comando T-SQL. Es el marcador de fin de lote reconocido por todas las herramientas de SQL interactivo de Microsoft (Management Studio, isql, osql). Para manejarlo, tendrá que escribir su propio analizador para dividir cada bloque de texto en el archivo entre las declaraciones GO y enviarlos a la base de datos como comandos separados.

Cómo implementar su analizador depende de usted. Puede ser simple (leer en cada línea a la vez, detectar líneas que consistan en nada más que GO y espacios en blanco) o complejo (señalar todas las declaraciones y determinar si un GO es una declaración genuina o un poco de texto dentro de una cadena o comentario multilínea).

Personalmente fui con la primera opción. Maneja el 99% de todos los archivos SQL que es probable que encuentre sin problemas. Si quieres irte todo el rato y escribir un tokeniser, estoy seguro de que muchas personas ya lo han hecho, solo Google.

Ejemplo:

using(var reader = new SqlBatchReader(new StreamReader(dmlFile))) { string batch; while((batch = reader.ReadBatch()) != null) { var cmd = new SqlCommand(batch, conn, trans) { CommandType = CommandType.Text }; cmd.ExecuteNonQuery(); } } class SqlBatchReader : IDisposable { private TextReader _reader; public SqlBatchReader(TextReader reader) { _reader = reader; } /// <summary> /// Return the next command batch in the file, or null if end-of-file reached. /// </summary> public string ReadBatch() { // TODO: Implement your parsing logic here. } }


Terminé escribiendo una implementación de un StringReader para hacer esto.

Lo maneja:

  1. Pasar por alto el GO incluido en los comentarios del tablero
  2. Saltar el GO pasado contenido en los comentarios de slash star
  3. Saltar el GO pasado contenido en literales (es decir, comillas simples)
  4. Saltar el GO pasado en los nombres de columna, etc.

Por lo tanto, solo detectará la palabra clave GO cuando se utilice como separador de lotes. Esto significa que divide el texto SQL correctamente.

También se maneja si ha agregado un terminador de sql (punto y coma) a la palabra GO

Puedes encontrar el código here :

Lo usas así:

using (var reader = new SqlCommandReader(scriptContents)) { var commands = new List<string>(); reader.ReadAllCommands(c => commands.Add(c)); // commands now contains each seperated sql batch. }