【问题标题】:Correct use of Try Catch for the SQL connection in C#在 C# 中正确使用 Try Catch 进行 SQL 连接
【发布时间】:2018-10-29 09:25:12
【问题描述】:

这段代码在 Try/Catch 方面是否正确?我需要评估操作是否完成以通知用户结果,因此我将获取 bool 值以了解连接是否成功。

    public static bool CreateSQLDatabaseTable()
    {
        var connString = "Server=localhost\\SQLEXPRESS;Integrated Security = SSPI; database = MyDB";
        string cmdText = "SELECT count(*) as Exist from INFORMATION_SCHEMA.TABLES where table_name =@Product";
        try
        {
            using (var sqlConnection = new SqlConnection(connString))
            {
                using (var sqlCmd = new SqlCommand(cmdText, sqlConnection))
                {
                    sqlCmd.Parameters.Add("@Product", System.Data.SqlDbType.NVarChar).Value = "Product";
                    sqlConnection.Open();
                    sqlCmd.ExecuteScalar();
                    if ((int)sqlCmd.ExecuteScalar() != 1)
                    {
                        using (SqlCommand command = new SqlCommand("CREATE TABLE Product (Id INT, UserId TEXT, CreationDate TEXT, Name TEXT)", sqlConnection))
                        {
                            command.ExecuteNonQuery();
                            return true;
                        }
                    }
                }

            }
            return false;
        }
        catch
        {
            return false;
        }
    }

【问题讨论】:

  • catch 实际上应该捕获一个可能抛出的异常(并对其做一些处理,而不是吞下它)
  • 在这个方法调用完成后,我会检查真/假并回复用户。可以吗?
  • 另外,不要将 TEXT 数据类型用于已弃用的 SQL 列。使用VARCHAR / VARCHAR( MAX )
  • 如果调用该方法返回false,如何知道表是否已经存在或者是否抛出异常?
  • @Alex:更好的 NVARCHAR / NVARCHAR(MAX),那么他在国际化方面永远不会有问题。

标签: c# sql sql-server exception-handling try-catch


【解决方案1】:

你的方法实际上可以有 3 个结果:

  1. 表创建成功(方法返回true)
  2. 表已经存在(方法返回false)
  3. 尝试创建表时出错(抛出异常)

所以你应该在这个方法之外处理异常,你不应该盲目地捕获所有的异常。您应该只处理SqlException,以便不会处理其他异常。此外,您应该在某处记录异常作为一种好习惯。

有关SqlException的更多信息
https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlexception(v=vs.110).aspx

public static bool CreateSQLDatabaseTable()
{
    var connString = "Server=localhost\\SQLEXPRESS;Integrated Security = SSPI; database = MyDB";
    string cmdText = "SELECT count(*) as Exist from INFORMATION_SCHEMA.TABLES where table_name =@Product";

    using (var sqlConnection = new SqlConnection(connString))
    {
        using (var sqlCmd = new SqlCommand(cmdText, sqlConnection))
        {
            sqlCmd.Parameters.Add("@Product", System.Data.SqlDbType.NVarChar).Value = "Product";
            sqlConnection.Open();
            sqlCmd.ExecuteScalar();
            if ((int)sqlCmd.ExecuteScalar() != 1)
            {
                using (SqlCommand command = new SqlCommand("CREATE TABLE Product (Id INT, UserId TEXT, CreationDate TEXT, Name TEXT)", sqlConnection))
                {
                    command.ExecuteNonQuery();
                    return true;
                }
            }
        }
    }

    return false;
}

public static void Main()
{
    try
    {
        bool wasCreated = CreateSQLDatabaseTable();
    }
    catch (SqlException ex)
    {
        // Handle the SQL Exception as you wish
        Console.WriteLine(ex.ToString());
    }
}

【讨论】:

  • 将 try catch 移到方法本身之外并改为方法调用者的参数是什么?
  • 它在技术上可能在方法内部,但这提供了处理上面列出的所有 3 个结果的灵活性。在@positive-perspective 初始示例中,如果出现错误或表已经存在,他都会返回 false。我不认为这是预期的实现。如果 try catch 在方法内部移动,则仅在发生错误的情况下才应返回 false,否则应始终返回 true。这会降低灵活性。
  • 这会执行两次查询!
【解决方案2】:

我会通过一个查询来解决这样的问题,该查询本身会检查存在并返回它是否已创建。

    public static bool CreateSQLDatabaseTable() {
        var connString = "...";
        const string tableName = "Product";
        string cmdText = $"IF EXISTS (SELECT TOP(1) 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_CATALOG = DB_NAME() AND TABLE_SCHEMA = 'dbo' AND TABLE_NAME = '{tableName}' AND TABLE_TYPE = 'BASE TABLE') BEGIN\r\n" +
                         $"  SELECT CAST(0 AS BIT) AS CreatedNow\r\n" +
                         $"END ELSE BEGIN\r\n" +
                         $"  CREATE TABLE dbo.{tableName}(Id INT, CreatorId INT, CreationDate DATETIME, CreationDateUtc DATETIME, Name NVARCHAR)\r\n" +
                         $"  SELECT CAST(1 AS BIT) AS CreatedNow\r\n" +
                         $"END";

        using (var sqlConnection = new SqlConnection(connString)) {
            using (var sqlCmd = new SqlCommand(cmdText, sqlConnection)) {
                sqlConnection.Open();
                return (bool)sqlCmd.ExecuteScalar();
            }
        }
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-04-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-08
    • 1970-01-01
    相关资源
    最近更新 更多