【问题标题】:How send SQL request with "go" in C# code如何在 C# 代码中使用“go”发送 SQL 请求
【发布时间】:2021-12-06 05:36:23
【问题描述】:

我有一些 SQL 请求:

go
Update dbo.Parameter set ValueAsStr = '{
 "CreateDepoUrl": "https://sandbox.sg...../",
 "CheckDepoStatusUrl": "https://sandbox.sg..../",
 "CreatePayoutUrl": "https://sandbox.sg....../",
 "CheckPayoutStatusUrl": "https://sandbox.sg..../",
 "PayoutTerminalIds": {
....
go

如果我在 SSMS 中发送此请求,一切正常
我从 C# 代码发送 SQL 请求的方法:

public static void SendToMainSqlRequest(MainDbContext mainDbContext, string queryString)
{

    using (var conn = mainDbContext.Database.GetDbConnection())
    {
        conn.Open();

        var command = mainDbContext.Database.GetDbConnection().CreateCommand();
        command.CommandText = queryString;
        command.CommandType = CommandType.Text;

        int number = command.ExecuteNonQuery();
        Console.WriteLine("count of updates: {0}", number);
        
        conn.Close();
    }
}

当我在 C# 代码中发送请求时出现异常:

'.' 附近的语法不正确

如果我删除“dbo”。在 SQL 请求中我得到一个异常:

'=' 附近的语法不正确

表名和字段名正确。没有错别字。
我该如何解决这个问题?
谢谢!

【问题讨论】:

  • "GO" 不是 SQL 命令,它是一个只有 SSMS 知道的分隔符。所以你需要过滤掉它
  • GO 不是 T-SQL 运算符;用 C# 编写 SQL 时,它们不应该出现在您的 SQL 中。 GO 是批量分离,被 IDE 识别,如 SSMS、SQLCMD、ADS、DBeaver 等。
  • 逐行阅读脚本。如果读取了“GO”,则执行您收集到的语句,然后通过相同的逻辑继续读取直到结束。这就是 SSMS 的作用。
  • 简单地过滤掉“GO”不会在任何地方都有好处。有些语句应该是批处理中的第一个语句,因此在“GO”之后没关系,但如果“GO”被过滤掉并且语句成为批处理中的中间语句,它将无法工作。

标签: c# sql-server entity-framework


【解决方案1】:

我使用下面的代码来做到这一点:

...
var lines = GoSplitter.Split(queryString);
foreach(var line in lines)
{
    command.CommandText = line;
    command.CommandType = CommandType.Text;
    int number = command.ExecuteNonQuery();
    // process number if needed
}
...

GoSplitter 类(抱歉 cmets 是法语)

using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text.RegularExpressions;

namespace DatabaseAndLogLibrary.DataBase
{
    /// <summary>
    /// Coupe un texte SQL en fonction des GO
    /// Prend en compte les Go dans les chaines ou les commentaires SQL qui eux doivent être ignorés
    /// Retire aussi les instruction SQL : USE
    /// </summary>
    internal class GoSplitter
    {
        /// <summary>
        /// Pour détection des instruction USE
        /// </summary>
        private static Regex regUse = new Regex(@"^\s*USE\s");

        /// <summary>
        /// Renvoie la liste des instructions SQL séparé en fonction des GO dans le script d'origine
        /// Prend en compte les Go dans les chaines ou les commentaires SQL qui eux doivent être ignorés
        /// </summary>
        /// <param name="fileContent"></param>
        /// <returns></returns>
        public static IEnumerable<string> Split(string fileContent)
        {
            if (string.IsNullOrWhiteSpace(fileContent))
            {
                yield break;
            }

            string res;
            var currentState = EState.Normal;
            List<Marker> markers = LoadMarker(fileContent).OrderBy(x => x.Index).ToList();

            int index0 = 0;
            for (int i = 0; i < markers.Count; i++)
            {
                switch (currentState)
                {
                    case EState.Normal:
                        switch (markers[i].Event)
                        {
                            case EMarker.Go:
                                res = fileContent.Substring(index0, markers[i].Index - index0).Trim();
                                res = ReplaceUse(res);
                                if (!string.IsNullOrWhiteSpace(res))
                                {
                                    yield return res;
                                }

                                index0 = markers[i].Index + 2;  // 2 lettres dans go
                                break;
                            case EMarker.Quote:
                                currentState = EState.InText;
                                break;
                            case EMarker.Comment:
                                currentState = EState.InComment;
                                break;
                        }

                        break;
                    case EState.InText:
                        if (markers[i].Event == EMarker.Quote)
                        {
                            currentState = EState.Normal;
                        }

                        break;
                    case EState.InComment:
                        if (markers[i].Event == EMarker.EndComment)
                        {
                            currentState = EState.Normal;
                        }

                        break;
                }
            }

            res = fileContent.Substring(index0, fileContent.Length - index0).Trim();
            res = ReplaceUse(res);
            if (!string.IsNullOrWhiteSpace(res))
            {
                yield return res;
            }
        }

        /// <summary>
        /// Charge les points clés du script
        /// </summary>
        /// <param name="fileContent"></param>
        /// <returns></returns>
        private static  IEnumerable<Marker> LoadMarker(string fileContent)
        {
            var regGo = new Regex(@"\bgo\b", RegexOptions.Multiline | RegexOptions.IgnoreCase);
            foreach(var m in  regGo.Matches(fileContent).Where(x => x.Success).Select(x => new Marker() { Index = x.Index, Event = EMarker.Go }))
            {
                yield return m;
            }

            var regQuote = new Regex(@"'", RegexOptions.Multiline);
            foreach (var m in regQuote.Matches(fileContent).Where(x => x.Success).Select(x => new Marker() { Index = x.Index, Event = EMarker.Quote }))
            {
                yield return m;
            }

            var regComment1 = new Regex(@"-(-)+[\s\S]*?$", RegexOptions.Multiline);
            foreach (Match m in regComment1.Matches(fileContent).Where(x => x.Success))
            {
                yield return new Marker() { Index = m.Index, Event = EMarker.Comment };
                yield return new Marker() { Index = m.Index + m.Length, Event = EMarker.EndComment };
            }

            var regComment2 = new Regex(@"/\*[\s\S]*?\*/", RegexOptions.Multiline);
            foreach (Match m in regComment2.Matches(fileContent).Where(x => x.Success))
            {
                yield return new Marker() { Index = m.Index, Event = EMarker.Comment };
                yield return new Marker() { Index = m.Index + m.Length, Event = EMarker.EndComment };
            }
        }

        /// <summary>
        /// Remplace les instructions using
        /// </summary>
        /// <param name="sqlLine"></param>
        /// <returns></returns>
        private static string ReplaceUse(string sqlLine)
            => regUse.Replace(sqlLine, string.Empty); // .Replace("USE", "---");

        [DebuggerDisplay("{Index} - {Event}")]
        private class Marker
        {
            public int Index {get; set;}
            public EMarker Event { get; set; }
        }

        /// <summary>
        /// les types de détection qui aggissent sur l'automate
        /// </summary>
        private enum EMarker
        {
            Go,
            Quote,
            Comment,
            EndComment
        }

        /// <summary>
        /// Les états de l'automate
        /// </summary>
        private enum EState
        {
            Normal,
            InComment,
            InText
        }
    }
}

享受吧!

【讨论】:

    【解决方案2】:

    您可以使用 SQL Server 管理对象库来执行带有 GO 语句的 SQL 命令。我们在内部使用它来执行数据库迁移脚本来更新我们的数据库架构。

    Here's the library.

    以及一些演示如何使用它的示例代码:

    using System;
    using Microsoft.SqlServer.Management.Common;
    using Microsoft.SqlServer.Management.Smo;
    using Microsoft.Data.SqlClient;
    
    using (var connection = new SqlConnection(connectionString))
    {
        connection.Open();
        var server = new Server(new ServerConnection(connection));
    
        //this is to get script output (if you have any)
        server.ConnectionContext.ServerMessage += (sender, eventArgs) =>
        {
            Console.WriteLine(eventArgs.Error.Message);
        };
    
        server.ConnectionContext.ExecuteNonQuery("some SQL with GO statements");
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-11-03
      • 1970-01-01
      • 1970-01-01
      • 2021-08-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-22
      相关资源
      最近更新 更多