2013-03-25 16 views
7

Tôi có một ứng dụng C# để gọi các thủ tục lưu trữ SQL Server khác nhau để thực hiện nhiều công việc xuất và nhập dữ liệu vào SQL Server Cơ sở dữ liệu 2008 R2.Làm thế nào để chuỗi nhiều câu lệnh T-SQL (cách nhau bởi GO) thành một cuộc gọi tới SQL bằng cách sử dụng SqlCommand

Tất cả đều ổn, không sao cả. Và ứng dụng của tôi gọi chúng là tốt với tất cả các thông số, v.v.

Để "hỗ trợ người dùng", tôi đang mã hóa nút để thêm tất cả các thủ tục đã lưu vào cơ sở dữ liệu được cấu hình. Để kết thúc này, tôi đã tạo một tập lệnh dọc theo các dòng:

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 

Khi tôi chạy nó trong SQL Server Management Studio, nó chạy tốt, không có vấn đề gì cả.

Tuy nhiên trong C# ứng dụng của tôi, một ngoại lệ được ném và tôi nhận được một tàu tải trọng của lỗi như sau:

cú pháp sai gần 'GO'.
Cú pháp không chính xác gần 'GO'.
Cú pháp không chính xác gần 'GO'.
Cú pháp không chính xác gần 'GO'.
Cú pháp không chính xác gần 'GO'.
Cú pháp không chính xác gần 'GO'.
'TẠO/THAY THẾ THỦ TỤC' phải là câu lệnh đầu tiên trong chuỗi truy vấn.
Không thể sử dụng câu lệnh RETURN với giá trị trả lại trong ngữ cảnh này.
Không thể sử dụng câu lệnh RETURN với giá trị trả lại trong ngữ cảnh này.
Cú pháp không chính xác gần 'GO'.
Phải khai báo biến vô hướng "@MessageText".
Phải khai báo biến vô hướng "@ListOfIDsToImport".
Phải khai báo biến vô hướng "@SourceDataFolder".
Phải khai báo biến vô hướng "@SourceDataFolder".
Phải khai báo biến vô hướng "@SequenceNo".
Phải khai báo biến vô hướng "@UserID".
Phải khai báo biến vô hướng "@SequenceNo".
Phải khai báo biến vô hướng "@UserID".
Phải khai báo biến vô hướng "@ListOfIDsToImport".
Phải khai báo biến vô hướng "@ListOfIDsToImport".
Phải khai báo biến vô hướng "@ListOfIDsToImport".
Phải khai báo biến vô hướng "@MessageText".
Phải khai báo biến vô hướng "@MessageText".
Phải khai báo biến vô hướng "@MessageText".
Cú pháp không chính xác gần 'GO'.
Tên biến '@PS_DEFAULT' đã được khai báo. Tên biến phải là duy nhất trong chuỗi truy vấn hoặc thủ tục được lưu trữ.
Tên biến '@PS_ERROR_MSG' đã được khai báo. Tên biến phải là duy nhất trong chuỗi truy vấn hoặc thủ tục được lưu trữ.
Tên biến '@PS_ERROR_SEVERITY' đã được khai báo. Tên biến phải là duy nhất trong chuỗi truy vấn hoặc thủ tục được lưu trữ.
Phải khai báo biến vô hướng "@SequenceNo".
Cú pháp không chính xác gần 'GO'.

(Đây là những gì trong ex.Message như bị chặn bởi khối catch trong mã bên dưới).

Mã của tôi rất đơn giản như sau:

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(); 
    } 

(Các thay thế ở trên chỉ đơn giản là thay thế placeholder trong dòng SỬ DỤNG ở phía trên cùng của kịch bản và nó hoạt động như tôi có thể nhìn thấy khi tôi bước qua và hơn dòng đó).

Vì vậy, về cơ bản, tôi đang làm gì sai vì bản thân SQL có vẻ ổn?

Rất cám ơn

+0

bạn về cơ bản cần phải chia tay bạn tập lệnh ở mọi 'GO' và thực hiện từng" tập lệnh con "dưới dạng một cuộc gọi riêng biệt tới' SqlCommand.ExecuteNonQuery() ', để đáp ứng các yêu cầu như * 'TẠO/THAY THẾ' phải là câu lệnh đầu tiên trong một chuỗi truy vấn. * –

Trả lời

1

Điều này Link sẽ cho bạn câu trả lời.

+0

Câu trả lời thứ hai về liên kết này (sử dụng SMO) đã cho tôi những gì tôi muốn và làm việc hoàn hảo! Cảm ơn :-) – Mike

+9

-1; Khi liên kết bị rots, câu trả lời này sẽ là vô dụng. Hai câu trả lời còn lại cung cấp thông tin tương tự, không có điểm yếu này. –

3

này nên dễ ...

thoát khỏi GO, đó là SSMS cú pháp cụ thể, ngôn ngữ SQL không đòi hỏi hay hỗ trợ nó, chứ không phải bạn nên chấm dứt cá nhân của bạn tạo ra các kịch bản với ; . Hãy cho tôi biết thế nào mà đi.

+0

Cảm ơn - điều đó đã xóa tất cả các lỗi liên quan đến câu lệnh GO, tuy nhiên tất cả các lỗi còn lại vẫn tồn tại. Bất kỳ ý tưởng nào khác? SQL là tốt, tôi biết nó là, như SSMS xử lý tất cả tốt. – Mike

+1

Điều đó sẽ không hoạt động - vì những thứ như * TẠO/THAY THẾ THỦ TỤC 'phải là câu lệnh đầu tiên trong một chuỗi truy vấn. * Sẽ không được sửa với điều này * thả tất cả 'GO' * cách tiếp cận .... –

+0

I viết sp của tôi là ... CREATE PROCEDURE [dbo]. [spMyProc1] (@VariousParams varchar (100), @ResultText varchar (4000) OUTPUT) chú ý đến(). Hãy thử điều đó và xem liệu nó có giải quyết được không. – RandomUs1r

2

Bạn KHÔNG THỂ đặt một đối tượng ADO.NET duy nhất để thực thi tập lệnh chứa các thuật ngữ lô ("GO") theo như tôi biết. Bạn sẽ phải làm một trong hai điều:

  1. Tạo một đối tượng SQL Management Studio và chạy nó ở chế độ nền. Tôi biết thư mục SQL Management Studio có DLL có thể làm việc từ SSMS. Tôi đã tạo ra mã .NET để mở SSMS cho ai đó và sắp tải nó, nhưng không thực thi nó trực tiếp.

  2. Thực hiện cho từng phương pháp và tách tập lệnh SQL của bạn để tạo một mảng đối tượng từ câu lệnh 'GO' vào bộ nhớ trong Danh sách hoặc tương tự. Sau đó, lặp qua danh sách đó với câu lệnh 'foreach' để thực hiện từng câu lệnh với các khối try/catch thích hợp.

0

Nếu tập lệnh xuất phát từ một số Stream (chẳng hạn như từ tài nguyên được nhúng qua Assembly.GetManifestResourceStream(), từ FileStream hoặc MemoryStream). Bạn có thể sử dụng sau đây để phân chia các SSMSSQLCMD kịch bản thực thi mà có thể bao gồm 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; 
     } 
    } 
} 

Phương pháp ExecuteBatch tuần tự thực hiện các phần kịch bản qua SqlCommand:

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

     cmd.CommandText = part; 
     cmd.ExecuteNonQuery(); 
    } 
} 
Các vấn đề liên quan