1

我有以下代码连接到数据库 > 运行存储过程 > 然后继续。

我相信数据库编程很容易出错,所以防御很重要以下是防御性的吗?(或者可以改进吗?)

public int RunStoredProc()
{
SqlConnection conn = null;
SqlCommand dataCommand = null;
SqlParameter param = null;
int myOutputValue;

try
{
    conn = new SqlConnection(ConfigurationManager.ConnectionStrings["IMS"].ConnectionString);                  
    conn.Open();
    dataCommand = conn.CreateCommand();
    dataCommand.CommandType = CommandType.StoredProcedure;
    dataCommand.CommandText = "pr_blahblah";
    dataCommand.CommandTimeout = 200; //seconds
    param = new SqlParameter();
    param = dataCommand.Parameters.Add("@NumRowsReturned", SqlDbType.Int);
    param.Direction = ParameterDirection.Output;
    dataCommand.ExecuteNonQuery();
    myOutputValue = (int)param.Value;

    return myOutputValue;
}
catch (SqlException ex)
{
    MessageBox.Show("Error:" + ex.Number.ToString(), "Error StoredProcedure");
    return 0;
}
finally
{
    if (conn != null)
    {
        conn.Close();
        conn.Dispose();
    }
}
}

现在的代码如下所示

我已经尝试使用每个人提供的所有帮助,并且上面的代码现在已经修改为以下我希望现在足够防御的代码:

public SqlConnection CreateConnection()
{
    SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["IMS"].ConnectionString);
    return conn;
}
public int RunStoredProc()
{
    using (var conn = CreateConnection())
    using (var dataCommand = conn.CreateCommand()) 
    {
            conn.Open();
            dataCommand.CommandType = CommandType.StoredProcedure;
            dataCommand.CommandText = "pr_BankingChargebacks";
            dataCommand.CommandTimeout = 200; //5 minutes
            SqlParameter param = new SqlParameter();
            param = dataCommand.Parameters.Add("@NumRowsReturned", SqlDbType.Int);
            param.Direction = ParameterDirection.Output;
            dataCommand.ExecuteNonQuery();
            int myOutputValue = (int)param.Value;

            return myOutputValue;

    } 
}
4

5 回答 5

7

尝试使用using此类事物的构造。

using(var conn = new SqlConnection(ConfigurationManager.ConnectionStrings["IMS"].ConnectionString)
{
}

一旦你这样做了,我认为你将处于正确的“防御”水平。同样,尝试对任何必须处理的东西做同样的事情(比如命令)

于 2012-07-27T11:49:56.017 回答
4
  • 无需同时调用.Close().Dispose()
  • 更喜欢using块而不是try-finally
  • 处置命令对象
  • 我会删除 catch 子句。它不属于这里(尽管 YMMV)。

如果您要在各处编写此代码,请停止。至少创建一个小型辅助类来执行此操作,或者使用像MassiveDapperPetaPoco这样的轻量级“ORM” 。有关 ADO.Net 帮助程序类的示例,请参阅https://github.com/jhgbrt/yadal/blob/master/Net.Code.ADONet.SingleFile/Db.cs

于 2012-07-27T11:53:44.633 回答
3

我会注意到的主要事情是MessageBox数据库访问代码。我想不出一个有用的场景。让异常上升。不要抓住那个。

作为通用模板:

using(var conn = CreateConnection())
using(var cmd = conn.CreateCommand())
{
    // setup cmd and the parameters
    conn.Open();
    cmd.ExecuteNonQuery();
    // post-process cmd parameters (out/return/etc)
}

注意:没有Close(),没有catch;所有的finally都由using. 简单得多;更难出错。

另一个需要强调的是使用工厂方法来创建连接;不要放:

new SqlConnection(ConfigurationManager.ConnectionStrings["IMS"].ConnectionString)

融入每一种方法;毕竟......这可能会改变,这是不必要的重复。

于 2012-07-27T11:53:31.060 回答
1

如果 MessageBox.Show("Error:" + ex.Number.ToString(), "Error StoredProcedure");是您将如何处理异常,那么您不会记录甚至检索实际的异常详细信息。

于 2012-07-27T11:52:43.967 回答
1

除了 manojlds 的建议之外,我建议您自己制作一些可重用的辅助方法来调用数据库。例如,让自己成为一个读取连接字符串、创建连接并打开它的方法。不要到处重复基础设施的东西。

您可以对调用存储过程或命令文本执行相同操作。

于 2012-07-27T11:53:19.733 回答