使用C#函数和执行存储过程的SqlCommand进行故障

时间:2014-09-23 10:06:30

标签: c# sql-server

这是我在这里的第一篇文章。我真的很喜欢这个地方,到目前为止我发现了很多有趣的东西,所以我决定登机!

我在C#中尝试使用递归调用时遇到了一些奇怪的事情。这就是我正在做的事情。

//routine for downloading Phases
public static int DownloadPhases(string competitionId, string competitionCountry, string competitionPhase = "")
{
    DataTable dt = new DataTable();

    DateTime phaseStart = DateTime.Now, phaseEnd = DateTime.Now, outDate;

    XmlDocument xmlDoc = new XmlDocument();
    bool isDate = false, isNumeric = false;

    string url = "", phaseId = "", phaseCode = "", phaseName = "", phaseDesc = "";
    int phaseSort = 0, outNum = 0, result = 0;

    // load structure for inserting new Phases
    SqlUtilities.sqlLoadDt(ConfigurationManager.AppSettings["sqlSel_insCompetitionsPhase"], ref dt);

    DataColumn[] keyColumn2 = new DataColumn[3];
    keyColumn2[0] = dt.Columns["phase_ID"];
    keyColumn2[1] = dt.Columns["phase_Competition"];
    keyColumn2[2] = dt.Columns["phase_Country"];

    dt.PrimaryKey = keyColumn2;

    try
    {
        if (competitionPhase == "")
            url = buildUrl("15", "", "", competitionCountry, competitionId);
        else
            url = buildUrl("15", "", "", competitionCountry, competitionPhase);

        loadXml(xmlDoc, url);

        // set a nodelist with all the <category> tags for Phases
        XmlNodeList competitions = xmlDoc.GetElementsByTagName("Item");

        // for each node in the the nodelist, get all the infos about it
        foreach (XmlNode competition in competitions)
        {
            //phase
            phaseId = competition.Attributes.GetNamedItem("id").Value.ToString();
            phaseCode = competition.Attributes.GetNamedItem("code").Value.ToString();
            phaseName = competition.Attributes.GetNamedItem("name").Value.ToString();
            phaseDesc = competition.Attributes.GetNamedItem("description").Value.ToString();

            isDate = DateTime.TryParse(competition.Attributes.GetNamedItem("comp_start").Value.ToString(), out outDate);

            if (isDate == true) 
                phaseStart = outDate;

            isDate = DateTime.TryParse(competition.Attributes.GetNamedItem("comp_end").Value.ToString(), out outDate);

            if (isDate == true) 
               phaseEnd = outDate;

            isNumeric = int.TryParse(competition.Attributes.GetNamedItem("sort").Value.ToString(), out outNum);

            if (isNumeric == true) 
               phaseSort = outNum;

            // adding competition to datatable dt
            if (phaseId != "")
            {
               try
               {
                   dt.Rows.Add(phaseId, competitionId, competitionCountry, phaseCode, phaseStart, phaseEnd, phaseDesc, phaseName, phaseSort);
                   result += 1;

                   if (phaseDesc.Contains("NOT LEAF"))
                      <b>DlData.DownloadPhases(competitionId, competitionCountry, phaseId);</b>
               }
               catch (Exception ex)
               {
                    ex.Message.ToString();
               }
               finally
               {
                    phaseId = "";
               }
           }
        } //end foreach phase
     }
     catch (Exception ex)
     {
         ex.Message.ToString();
     }
     finally
     {
          //call stored procedure to insert Phases
          SqlUtilities.sqlExecuteSp("dbo.usp_insCompetitionsPhase", dt);
     }

     return result;
}

这是SqlExecuteSp函数

public static void sqlExecuteSp(string cmdText, DataTable parDt)
{
  try
  {
    SqlConnection conn = new SqlConnection();

    SqlCommand comm = new SqlCommand();

    SqlParameter param = new SqlParameter();
    SqlTransaction trans;

    conn.ConnectionString = ConfigurationManager.ConnectionStrings["FTBLConnectionStringSuperUser"].ConnectionString;

    conn.Open();

    using (conn)
    {
      trans = conn.BeginTransaction();
      comm.CommandText = cmdText;
      comm.Connection = conn;
      comm.CommandType = CommandType.StoredProcedure;
      comm.Transaction = trans;

      param = comm.Parameters.AddWithValue("@dt", parDt);
      param.SqlDbType = SqlDbType.Structured;

      comm.ExecuteNonQuery();

      trans.Commit();
    }

    conn.Close();
  }
  catch (Exception ex)
  {
    ex.Message.ToString();
  }
}

当我尝试递归调用SqlExecuteSp函数时,它似乎正确执行它,但是我无法看到插入的新行,直到我删除第一行。

因此,如果我在SQL Server Management Studio中运行delete from tbl_competition_phases,它只删除&#34; old&#34;行,从现在开始,我可以看到第二次调用插入的行。

我认为这是由于交易不完整所致,所以正如您所看到的,我添加了一个交易对象,没有结果。

我知道c#中的递归调用并不是最好的事情。无论如何,在这种情况下,我非常确定不会超过2个电话,所以我认为它不会成为一个问题。

有什么建议吗?

非常感谢!

达米亚诺

1 个答案:

答案 0 :(得分:0)

我想我已经发现了错误可能是什么 - 在sqlExecuteSp方法中你将conn放在一个使用块中(声明不正确) - 但是在它被处理之后在它之外调用它。这将导致异常。正如我在评论中所说的那样 - 你吞下异常的事实就是把这个隐藏起来。

尝试使用sqlExecuteSp方法

public static void sqlExecuteSp(string cmdText, DataTable parDt)
{
    using (SqlConnection conn = new SqlConnection())
    {
        using (SqlCommand comm = new SqlCommand())                    
        {
            conn.ConnectionString = ConfigurationManager.ConnectionStrings["FTBLConnectionStringSuperUser"].ConnectionString;
            conn.Open();

            using (SqlTransaction trans = conn.BeginTransaction())
            {
                comm.Connection = conn;
                comm.CommandType = CommandType.StoredProcedure;
                comm.Transaction = trans;

                SqlParameter param = comm.Parameters.AddWithValue("@dt", parDt);
                param.SqlDbType = SqlDbType.Structured;

                comm.ExecuteNonQuery();

                trans.Commit();
            }
        }

        conn.Close();
    }

}

这可能不是您所看到的行为的原因 - 但在程序运行时肯定会导致错误/意外行为。

一些提示

  • 包含可以使用块处理的对象以确保它们 即使发生错误也会被处置(例如,如果您的连接字符串 在配置文件中丢失了)并使用正确的方法执行此操作,如我的示例所示
  • 缩小变量的范围(仅在需要时声明它们) - 减少它们必须存在的时间并使代码更具可读性(例如,我将SqlParameter声明向下移动到仅需要的位置)
  • 最后不要使用try catch,除非它是更广泛的异常处理框架的一部分 - 或者只有当你想要记录异常并且如果你正在记录重新抛出以便错误冒泡时。通过在不需要的地方使用它,您可以隐藏错误,这些错误可以帮助您诊断问题。有时它值得单独使用try / finally来确保运行一些代码 - 注意你不必拥有catch块。 this问题对此有一些有用的解读