【发布时间】:2020-04-14 16:19:50
【问题描述】:
我有一个类似的存储过程
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)逻辑的存储过程?
PS。我知道我可以通过 c# 在另一个 SQL 脚本中删除存储过程,但我想在一个脚本中执行它。另请注意,我有 SQL Server 2014,而不是像 2016 等较新的版本(因为我的公司,我知道它很烂)
【问题讨论】:
-
仅供参考,您应该避免使用
sp_前缀;它是 Microsoft 为 Special 程序保留的,因此您的 SP 可能有一天会突然停止工作(如果 Microsoft 引入了一个名为您的 SP 的特殊程序),并且使用sp_会导致性能下降:@ 987654321@ -
如果您在 Visual Studio 中创建一个数据库项目,然后部署生成的 DACPAC,而不是尝试通过代码这样做,那会好得多。这与避免使用诸如 FTP 之类的蛮力技术通过使用 MSDeploy 来部署网站本质上是相同的。此外,部署未知
string的内容可以说与代码中嵌入的 SQL 语句一样危险(如果不是更多的话)
标签: c# sql .net sql-server stored-procedures