2013-03-25 13 views
7

Mam aplikację komputerową C#, która wywołuje różne procedury składowane SQL Server w celu wykonania różnych prac związanych z eksportowaniem i importowaniem danych do serwera SQL Baza danych 2008 R2.Jak powiązać wiele instrukcji T-SQL (oddzielonych przez GO) w jedno wywołanie SQL za pomocą SqlCommand

Wszystko działa dobrze, bez problemu. I moja aplikacja nazywa je dobrze z wszystkimi parametrami itp.

Aby "pomóc użytkownikowi", koduję przycisk, aby dodać wszystkie zapisane procedury do skonfigurowanej bazy danych. W tym celu stworzyłem skrypt wzdłuż linii:

USE [%DATABASENAME%] 
GO   

IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[spMyProc1]') AND type in (N'P', N'PC')) 
DROP PROCEDURE [dbo].[spMyProc1] 
GO 

IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[spMyProc2]') AND type in (N'P', N'PC')) 
DROP PROCEDURE [dbo].[spMyProc2] 
GO 

IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[spMyProc3]') AND type in (N'P', N'PC')) 
DROP PROCEDURE [dbo].[spMyProc3] 
GO 

SET ANSI_NULLS ON 
GO 

SET QUOTED_IDENTIFIER ON 
GO 

CREATE PROCEDURE [dbo].[spMyProc1] 
     @VariousParams varchar(100), 
    @ResultText varchar(4000) OUTPUT 
AS 
BEGIN 
    -- Code removed for brevity 
END 

GO 
-- 

CREATE PROCEDURE [dbo].[spMyProc2] 
     @VariousParams varchar(100), 
    @ResultText varchar(4000) OUTPUT 
AS 
BEGIN 
    -- Code removed for brevity 
END 

GO 
-- 

CREATE PROCEDURE [dbo].[spMyProc3] 
     @VariousParams varchar(100), 
    @ResultText varchar(4000) OUTPUT 
AS 
BEGIN 
    -- Code removed for brevity 
END 

GO 

Gdy uruchomię to w SQL Server Management Studio, to działa dobrze, żadnych problemów.

Jednak w mojej aplikacji C#, jest wyjątek i uzyskać obciążenie łodzi błędów w następujący sposób:

Niepoprawna składnia w pobliżu „Go”.
Niepoprawna składnia w pobliżu "GO".
Niepoprawna składnia w pobliżu "GO".
Niepoprawna składnia w pobliżu "GO".
Niepoprawna składnia w pobliżu "GO".
Niepoprawna składnia w pobliżu "GO".
'CREATE/ALTER PROCEDURE' musi być pierwszą instrukcją w grupie zapytań.
W tym kontekście nie można użyć instrukcji RETURN z wartością zwracaną.
W tym kontekście nie można użyć instrukcji RETURN z wartością zwracaną.
Niepoprawna składnia w pobliżu "GO".
Należy zadeklarować zmienną skalarną "@MessageText".
Należy zadeklarować zmienną skalarną "@ListOfIDsToImport".
Należy zadeklarować zmienną skalarną "@SourceDataFolder".
Należy zadeklarować zmienną skalarną "@SourceDataFolder".
Należy zadeklarować zmienną skalarną "@SequenceNo".
Należy zadeklarować zmienną skalarną "@UserID".
Należy zadeklarować zmienną skalarną "@SequenceNo".
Należy zadeklarować zmienną skalarną "@UserID".
Należy zadeklarować zmienną skalarną "@ListOfIDsToImport".
Należy zadeklarować zmienną skalarną "@ListOfIDsToImport".
Należy zadeklarować zmienną skalarną "@ListOfIDsToImport".
Należy zadeklarować zmienną skalarną "@MessageText".
Należy zadeklarować zmienną skalarną "@MessageText".
Należy zadeklarować zmienną skalarną "@MessageText".
Niepoprawna składnia w pobliżu "GO".
Nazwa zmiennej "@PS_DEFAULT" została już zadeklarowana. Nazwy zmiennych muszą być unikalne w obrębie wsadowego zapytania lub procedury składowanej.
Nazwa zmiennej "@PS_ERROR_MSG" została już zadeklarowana. Nazwy zmiennych muszą być unikalne w obrębie wsadowego zapytania lub procedury składowanej.
Nazwa zmiennej "@PS_ERROR_SEVERITY" została już zadeklarowana. Nazwy zmiennych muszą być unikalne w obrębie wsadowego zapytania lub procedury składowanej.
Należy zadeklarować zmienną skalarną "@SequenceNo".
Niepoprawna składnia w pobliżu "GO".

(To, co jest w ex.Message jako złapany przez blok catch w poniższym kodzie).

Moje kodu jest bardzo proste, jak następuje:

bool retVal = false; 
    string command = Properties.Resources.MyApp_StoredProcedures.ToString().Replace("%DATABASENAME%", Properties.Settings.Default.DBName); 

    try 
    { 
     sqlCmd = new SqlCommand(command, csSQLConnection._conn); 
     sqlCmd.ExecuteNonQuery(); 
     retVal = true; 
    } 
    catch (Exception ex) 
    { 
     retVal = false; 
    } 
    finally 
    { 
     sqlCmd.Dispose(); 
    } 

(zastąpić wyżej po prostu zastępuje zastępczy w linii użytku na początku skryptu i działa jak widzę kiedy krok po kroku, a ponad ta linia).

W zasadzie, co robię źle, jak sam SQL wydaje się dobrze?

Dziękujemy

+0

Zasadniczo trzeba zerwać swoje skrypt przy każdym 'GO' i wykonanie każdego" podskryptu "jako osobne wywołanie' SqlCommand.ExecuteNonQuery() ', w celu spełnienia wymagań takich jak * 'CREATE/ALTER PROCEDURE' musi być pierwszą instrukcją w grupie zapytań. * –

Odpowiedz

1

Ten Link daje odpowiedź.

+0

Druga odpowiedź na ten link (przy użyciu SMO) dała mi to, co chciałem i działało idealnie! Dzięki :-) – Mike

+9

-1; Kiedy zgnije link, ta odpowiedź będzie bezużyteczna. Pozostałe dwie odpowiedzi dostarczają tych samych informacji, bez tej słabości. –

3

To powinno być łatwe ...

pozbyć GO, to SSMS specyficzny składni języka SQL nie wymaga lub wspierać go, raczej należy zakończyć swoją indywidualną tworzenie skryptów z ; . Daj mi znać, jak to działa.

+0

Dzięki - usunięto wszystkie błędy związane z instrukcjami GO, jednak pozostałe pozostały. Jakieś inne pomysły? SQL jest dobry, wiem, że tak jest, ponieważ SSMS przetwarza go w porządku. – Mike

+1

To nie zadziała - ponieważ rzeczy takie jak * CREATE/ALTER PROCEDURE 'muszą być pierwszą instrukcją w grupie zapytań. * Nie zostaną naprawione z tym * upuszczeniem całego podejścia 'GO' * .... –

+0

I napisz moje sp's jako ... CREATE PROCEDURE [dbo]. [spMyProc1] (@VariousParams varchar (100), @ResultText varchar (4000) OUTPUT) zauważ, że(). Spróbuj tego i zobacz, czy to rozwiązuje. – RandomUs1r

2

NIE MOŻNA ustawiać pojedynczego obiektu ADO.NET do wykonywania skryptu zawierającego terminatory wsadowe ("GO"), o ile wiem. Będziesz musiał wykonać jedną z dwóch czynności:

  1. Utwórz obiekt SQL Management Studio i uruchom go w tle. Wiem, że folder SQL Management Studio ma biblioteki DLL, które mogą działać z SSMS. Stworzyłem kod .NET, aby otworzyć SSMS dla kogoś i mieć zamiar go załadować, ale nie wykonuję go bezpośrednio.

  2. Wykonaj dla każdej metody i podziel swój skrypt SQL, aby utworzyć tablicę obiektów z instrukcji "GO" do pamięci na liście lub podobnej. Następnie wykonaj iterację na tej liście za pomocą instrukcji foreach, aby wykonać każdą z nich za pomocą odpowiednich bloków try/catch.

0

Jeśli skrypt pochodzi z Stream (takie jak z osadzonego zasobu poprzez Assembly.GetManifestResourceStream(), ze FileStream albo MemoryStream). Można użyć następujących podzielić SSMSSQLCMD skryptów wsadowych, które mogą zawierać GO:

public IEnumerable<string> GetScriptParts(Stream script) 
{ 
    const string reBatchSeparator = @"^(/\*.\*/)?\s*GO\s*(/\*.*\*/)?\s*(--.*)?$"; 

    using (StreamReader sr = new StreamReader(script)) 
    { 
     StringBuilder sb = new StringBuilder(); 
     while(!sr.EndOfStream) 
     { 
      string line = sr.ReadLine(); 
      if (!batchSeparator.IsMatch(line)) 
      { 
       sb.AppendLine(line); 
      } 
      else 
      { 
       string part = sb.ToString(); 
       if (!string.IsNullOrEmpty(part)) 
       { 
        yield return part; 
       } 
       sb.Clear(); 
      } 
     } 

     string part = sb.ToString(); 
     if (!string.IsNullOrEmpty(part)) 
     { 
      yield return part; 
     } 
    } 
} 

Sposób ExecuteBatch kolejno wykonuje części skryptu przez SqlCommand:

public void ExecuteBatch(SqlConnection conn, Stream script) 
{ 
    foreach (string part in GetScriptParts(script)) 
    { 
     SqlCommand cmd = conn.CreateCommand(); 

     cmd.CommandText = part; 
     cmd.ExecuteNonQuery(); 
    } 
} 
Powiązane problemy