【问题标题】:Is it OK to pass SQLCommand as a parameter?可以将 SQLCommand 作为参数传递吗?
【发布时间】:2010-04-23 13:49:38
【问题描述】:

我有一个业务层,可以像这样将 Conn 字符串和 SQLCommand 传递给数据层

    public void PopulateLocalData()
    {
       System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand();
       cmd.CommandType = System.Data.CommandType.StoredProcedure;
       cmd.CommandText = "usp_PopulateServiceSurveyLocal";
       DataLayer.DataProvider.ExecSQL(ConnString, cmd);
    }

DataLayer 然后像这样执行 sql

        public static int ExecSQL(string sqlConnString, System.Data.SqlClient.SqlCommand cmd)
    { 
        int rowsAffected;
        using (SqlConnection conn = new SqlConnection(sqlConnString))
        {
            conn.Open();
            cmd.Connection = conn;
            rowsAffected = cmd.ExecuteNonQuery();
            cmd.Dispose();
        }
        return rowsAffected;
    }

我是否可以像这样将 SQLCommand 作为参数传递,或者是否有更好更容易接受的方法。 我担心的一个问题是,如果在执行查询时发生错误,那么 cmd.dispose 行将永远不会执行。这是否意味着它将继续使用永远不会释放的内存?

更新:

按照 Eric 的建议,我更明确地划分了业务层和数据层,因此业务层中的方法如下所示

    public void PopulateLocalData()
    {
        DataLayer Data = new DataLayer(this.ConnString);
        Data.UpdateLocalData();
    }

DataLayer 中调用的方法如下所示。

        public void UpdateLocalData()
    {
        using (SqlConnection conn = new SqlConnection(this.ConnString))
        using(SqlCommand cmd = new SqlCommand())
        {
            cmd.CommandType = System.Data.CommandType.StoredProcedure;
            cmd.CommandText = "usp_PopulateServiceSurveyLocal";
            conn.Open();
            cmd.Connection = conn;
            cmd.ExecuteNonQuery();
        }
    }

这样很清楚,SQLCommand 和 SQLConnection 都将被正确处理。谢谢。

【问题讨论】:

    标签: c# sql


    【解决方案1】:

    理想情况下,您的业务层不应该知道数据层的实现细节。因此,无论您是使用SqlCommand 对象还是使用 NHibernate 之类的东西来实现数据层,都应该与业务层无关。从理论上讲,这使得“移出”数据层并将其替换为另一个数据层很容易。

    总结:将SqlCommand 从业务层传递到数据层在我看来不是好的做法。

    关于Dispose():如果您正在使用 using 语句(如using(SqlConnection ...)),Dispose() 方法会在 using 语句的末尾自动调用。您不必手动执行此操作。

    【讨论】:

    • 虽然没有 using(SqlCommand ...),但问题是如果出现故障,该命令可能无法正确处理。连接很好。
    • 据我所知, using(SqlCommand cmd = ...) 是完全有效的。
    【解决方案2】:

    创建命令的人应该负责处理它。最简单的方法是从ExecSql 中删除对cmd.Dispose 的调用,而是像这样调用你的函数:

    public void PopulateLocalData() 
    { 
       using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand())
       {
           cmd.CommandType = System.Data.CommandType.StoredProcedure; 
           cmd.CommandText = "usp_PopulateServiceSurveyLocal"; 
           DataLayer.DataProvider.ExecSQL(ConnString, cmd);
       }
    } 
    

    我担心的一个问题是,如果在执行查询时发生错误,cmd.dispose 行将永远不会执行。这是否意味着它将继续使用永远不会释放的内存?

    巧合的是,SqlClient.SqlCommand 不需要处理。然而,这是一个您不应该依赖的实现细节——一般规则仍然是:如果它实现了IDisposable,则将其丢弃。(例如,SqlCeClient.SqlCeCommand确实需要被处置...)

    【讨论】:

      【解决方案3】:

      你为什么不把它改成这样:

      public static int ExecProcedure(string sqlConnString, string procedureName)
      {
          using (var cmd = new System.Data.SqlClient.SqlCommand())
          {
              cmd.CommandType = System.Data.CommandType.StoredProcedure;
              cmd.CommandText = procedureName;
              int rowsAffected;
              using (SqlConnection conn = new SqlConnection(sqlConnString))
              {
                  conn.Open();
                  cmd.Connection = conn;
                  return cmd.ExecuteNonQuery();
              }
          }
      }
      

      您需要其他参数吗?创建重载,重构。共享功能中最多的代码。到处创建new System.Data.SqlClient.SqlCommand() 是错误的做法。

      【讨论】:

        【解决方案4】:

        首先,您可以将其更改为:

        public static int ExecSQL(string sqlConnString, System.Data.SqlClient.SqlCommand cmd)
        { 
            int rowsAffected;
            try
            {
                using (SqlConnection conn = new SqlConnection(sqlConnString))
                {
                    conn.Open();
                    cmd.Connection = conn;
                    rowsAffected = cmd.ExecuteNonQuery();
                }
            } finally {
                cmd.Dispose();
            }
            return rowsAffected;
        }
        

        此外,我通常比您更多地将业务层和数据层分开。我的业务层会在数据层调用一个方法“GetLocalSurvey”,它会处理所有的 SQL 废话。

        【讨论】:

          猜你喜欢
          • 2016-12-17
          • 2015-12-29
          • 1970-01-01
          • 1970-01-01
          • 2018-10-11
          • 1970-01-01
          • 2019-04-10
          • 1970-01-01
          • 2015-09-20
          相关资源
          最近更新 更多