繁体   English   中英

如何通过 C# 代码部署存储过程?

[英]How to deploy stored procedure via C# code?

我有一个像

IF (OBJECT_ID('sp_InsertDevice', 'P') IS NOT NULL) 
    DROP PROCEDURE sp_InsertDevice 
GO

CREATE PROCEDURE sp_InsertDevice
    @serialNumber NVARCHAR(8),
    @modelName NVARCHAR(40),
    @userId INT
AS
BEGIN
    INSERT INTO Device (SerialNumber, ModelName, UserID)
    VALUES (@serialNumber, @modelName, @userId)

    SELECT CAST(SCOPE_IDENTITY() AS INT);
END

和一个 C# 方法来部署它:

protected virtual async Task<bool> DeployStoredProcedure(string storedProcedureName)
{
    try
    {
        var dir = Directory.GetFiles(this.StoredProceduresPath);
        string storedProceduresPath = Directory.GetFiles(this.StoredProceduresPath).Where(x => x.Contains(storedProcedureName)).First();
        string storedProcedureScriptFull = File.ReadAllText(storedProceduresPath);

        SqlCommand insertProcedureCommand = new SqlCommand(storedProcedureScriptFull, this.SqlConnection)
                {
                    CommandType = CommandType.Text,
                    CommandTimeout = this.CommandTimeout
                };

        await this.EnsureConnectionOpened();
        await insertProcedureCommand.ExecuteNonQueryAsync();

        return true;
    }
    catch (Exception exception)
    {
        this.SqlConnection.Close();
        ExceptionDispatchInfo.Capture(exception).Throw();
        return false;
    }
}

一般而言,它将存储过程脚本读取为字符串并尝试像通常的 SQL 查询一样执行它。 一切正常,直到到达

await insertProcedureCommand.ExecuteNonQueryAsync();

并抛出异常

“GO”附近的语法不正确
CREATE/ALTER PROCEDURE' 必须是查询批处理中的第一条语句。

我注意到如果存储过程没有这部分

IF (OBJECT_ID('sp_InsertDevice', 'P') IS NOT NULL) 
    DROP PROCEDURE sp_InsertDevice 
GO

不会抛出任何异常并且该过程将成功部署。 所以问题可以表述为:如何通过 C# 代码部署包含 (IF EXISTS-DROP) 逻辑的存储过程?

附注。 我知道我可以通过 c# 在另一个 SQL 脚本中删除存储过程,但我想在一个脚本中完成它。 另请注意,我有 SQL Server 2014,而不是 2016 等较新版本(因为我的公司,我知道它很糟糕)

使用动态 SQL 的解决方法:

IF (OBJECT_ID('sp_InsertDevice', 'P') IS NOT NULL) 
    DROP PROCEDURE sp_InsertDevice 

EXEC(
'CREATE PROCEDURE sp_InsertDevice
    @serialNumber nvarchar(8),
    @modelName nvarchar(40),
    @userId int
AS
BEGIN
    INSERT INTO Device (SerialNumber, ModelName, UserID)
    VALUES (@serialNumber, @modelName, @userId)

    SELECT CAST(SCOPE_IDENTITY() AS INT);
END');

db<>小提琴演示


不幸的是,您将不得不将每个'内部存储过程加倍。 T-SQL 尚不支持here-strings i T-SQL

GO 不是有效的 SQL 命令,用于将 SQL 拆分为由 SQL Server 管理器在服务器上顺序执行的部分。

但是,使用 SQL Server 生成的脚本来分发数据库方案非常容易。

所以我把SQL自己生成的脚本在“GO”关键字上拆分,一一执行。

像这样的东西(这是一些“非常旧”的代码的副本,所以你应该使用 var 等清理一下):

                Regex regex = new Regex("GO\r\n",RegexOptions.Singleline);
                ArrayList updateCommands = new ArrayList(regex.Split(updateScript));

                using (SqlConnection con = GetNewConnection()) {
                    con.Open();
                    foreach(string commandText in updateCommands) {
                        if (string.IsNullOrWhiteSpace(commandText)) continue;
                        using (SqlCommand cmd = new SqlCommand(commandText, con)) {
                            cmd.ExecuteNonQuery();
                        }
                    } // foreach
                }

考虑使用SQL Server 管理对象 SqlClient不同, SMO包括识别GO批处理分隔符的方法。 SMO作为NuGet 包提供

下面是一个示例控制台应用程序,它使用Microsoft.SqlServer.Management.Common.ServerConnection.ExecuteNonQuery方法执行带有GO批处理分隔符的脚本。

using System;
using System.Data;
using System.Data.SqlClient;
using Microsoft.SqlServer.Management.Common;

class Example
{

    static void Main(string[] args)
    {
            var script = @"
IF (OBJECT_ID('sp_InsertDevice', 'P') IS NOT NULL) 
    DROP PROCEDURE sp_InsertDevice 
GO
CREATE PROCEDURE sp_InsertDevice
    @serialNumber nvarchar(8),
    @modelName nvarchar(40),
    @userId int
AS
BEGIN
    INSERT INTO Device (SerialNumber, ModelName, UserID)
    VALUES (@serialNumber, @modelName, @userId)

    SELECT CAST(SCOPE_IDENTITY() AS INT);
END
";
        try
        {
            using (var connection = new SqlConnection("Data Source=YourServer;Integrated Security=SSPI;Initial Catalog=YourDatabase"))
            {
                var serverConnection = new ServerConnection(connection);
                connection.Open();

                serverConnection.ExecuteNonQuery(script);
            }
        }
        catch
        {
            throw;
        }
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM