2009-10-08 101 views
10

我似乎无法执行使用DbCommand对象创建数据库的SQL。我究竟做错了什么?这里是我的代码:如何使用SqlConnection执行带注释和GO语句的SQL?

DbConnection connection; // initialized and opened elsewhere 
DbCommand cmd = connection.CreateCommand(); 
cmd.CommandText = sql; 
cmd.ExecuteNonQuery(); 

这里的错误:

The query syntax is not valid., near term '/', line 1, column 2. Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.Data.EntitySqlException: The query syntax is not valid., near term '/', line 1, column 2.

下面是该文件的第一部分。抛出异常时就只在第一行的评论:

/****** Object: Table [dbo].[User] Script Date: 10/08/2009 12:14:29 ******/ 
SET ANSI_NULLS ON 
GO 
SET QUOTED_IDENTIFIER ON 
GO 
CREATE TABLE [dbo].[User](
    [Id] [int] IDENTITY(1,1) NOT NULL, 
    [FirstName] [nvarchar](50) NULL, 
    [LastName] [nvarchar](50) NULL, 
    [EmailAddress] [nvarchar](100) NULL, 
CONSTRAINT [PK_User] PRIMARY KEY CLUSTERED 
(
    [Id] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 
GO 

同样的SQL脚本SQL管理Studio Express的执行就好了(事实上该应用产生的这个脚本!)。它只是Visual Studio自己的服务器资源管理器查询视图,并且来自我自己的代码,这似乎失败了。

+1

注:GO是不是一个SQL命令,它是一个命令至客户端工具(例如OSQL,查询分析器,或在这种情况下SMSS。),以打破脚本转换成单独的“批”。每批次都是对服务器的单独调用。 – 2009-10-08 22:24:46

+0

[执行大型SQL脚本(使用GO命令)]的可能副本](http://stackoverflow.com/questions/40814/execute-a-large-sql-script-with-go-commands) – 2016-06-09 02:15:00

回答

11

您需要使用SQL管理类而不是普通的SqlCommand。 This page shows you how to do it.如果你尝试自己解析SQL,那么总会有你错过的边缘情况。例如,如果代码中的字符串包含带前导和尾随回车符的单词“GO”会怎么样?

添加这些引用:

  • Microsoft.SqlServer.Smo
  • Microsoft.SqlServer.ConnectionInfo
  • Microsoft.SqlServer.Management.Sdk.Sfc(编辑
  • :不需要此参考)

然后你可以使用此代码:

string connectionString, scriptText; 
SqlConnection sqlConnection = new SqlConnection(connectionString); 
ServerConnection svrConnection = new ServerConnection(sqlConnection); 
Server server = new Server(svrConnection); 
server.ConnectionContext.ExecuteNonQuery(scriptText); 
+0

太棒了。我找不到要引用的'Microsoft.SqlServer.Management.Sdk.Sfc'程序集,但事实证明它不是必需的。 – 2009-10-09 03:39:56

8

下面的代码片段,我posted on my blog前一段时间,可能解决这个问题:

private static void RunScript(SqlConnection connection, string script) 
{ 
    Regex regex = new Regex(@"\r{0,1}\nGO\r{0,1}\n"); 
    string[] commands = regex.Split(script); 

    for (int i = 0; i < commands.Length; i++) 
    { 
     if (commands[i] != string.Empty) 
     { 
      using(SqlCommand command = new SqlCommand(commands[i], connection)) 
      { 
       command.ExecuteNonQuery(); 
       command.Dispose(); 
      } 
     } 
    } 
} 

它拆分SQL脚本为单独的命令并执行它们。我经常使用它来设置生成的SQL脚本的测试数据库。

+0

+1,但我不认为这是唯一的问题。错误是抱怨文件顶部的注释。 – 2009-10-08 20:29:30

+0

@Joel:我认为它*可能是因为它实际上抱怨了完整的陈述,而这恰恰是从评论开始的。虽然不能确定,所以我编辑过的文字不太确定它是否提供了解决方案。 – 2009-10-08 20:36:35

+0

GO批处理分隔符在空白区域有效,至少在SQL Server 2005的SMSS中是有效的。 – 2009-10-08 22:37:56

1

我觉得很奇怪,你得到的EntitySqlException ...

,你可以选择另一种解决方案,是通过osql命令行工具来执行这个脚本。 您可以创建一个System.Diagnostics.Process实例,并使用此进程调用osql,然后执行脚本。

System.Diagnostics.Process p = new System.Diagnostics.Process(); 

p.StartInfo.FileName = Environment.GetEnvironmentVariable ("COMSPEC"); 
p.StartInfo.UseShellExecute = false; 
p.StartInfo.ErrorDialog = false; 

p.StartInfo.CreateNoWindow = true; 
p.StartInfo.RedirectStandardInput = true; 
p.StartInfo.RedirectStandardError = true; 
p.StartInfo.RedirectStandardOutput = true; 

p.Start(); 

p.StandardInput.WriteLine ("echo off"); 
string command = @"osql -U -b -e -S " + servername + " -d " + databasename + " -i \'" + filename + "\'"; 
p.StandardInput.WriteLine (command); 
p.StandardInput.WriteLine ("exit"); 

p.WaitForExit(); 
+0

感谢您的提示。这可能在我的另一个场景中证明是有用的。 – 2009-10-09 03:39:01

0

在SQL Server中,只要你想用一个简单的空间分隔您可以连接尽可能多的查询,但对于您需要删除“GO” S。
例如:

BEGIN TRANSACTION SET QUOTED_IDENTIFIER ON SET ARITHABORT ON SET NUMERIC_ROUNDABORT OFF SET CONCAT_NULL_YIELDS_NULL ON SET ANSI_NULLS ON SET ANSI_PADDING ON SET ANSI_WARNINGS ON COMMIT BEGIN TRANSACTION $remove this GO here$ CREATE TABLE dbo.Tmp_Tralala( ERRID numeric (18,0) NOT NULL)) ON [PRIMARY] $remove this GO here$ IF EXISTS(SELECT * FROM dbo.Tralala) EXEC('INSERT INTO ..etc