【问题标题】:Exit out of datareader before else, in if-else statement在 if-else 语句中,在 else 之前退出 datareader
【发布时间】:2017-07-17 15:08:04
【问题描述】:

我想找到一种在 if 语句之后退出 datareader 的方法,以便我可以在 else 语句中执行插入查询。有办法吗?

我收到 dr 仍处于打开状态的错误,因此无法执行以下查询。

sVendorDetails.VendorID = insertcmd.ExecuteNonQuery();

代码如下:

public class VendorDetails
{
    int _VendorID;
    string _VendorName;

    public int VendorID
    {
        set { _VendorID = value; }
        get { return _VendorID; }
    }

    public string VendorName
    {
        set { _VendorName = value; }
        get { return _VendorName; }
    }
}

public VendorDetails VendorCheck(string sVendorName)
{
    SqlCommand cmd = new SqlCommand("dbo.usp_GetVendorByVendorName", myConnection);
    cmd.CommandType = CommandType.StoredProcedure;
    cmd.Parameters.Add(new SqlParameter("@VendorName", SqlDbType.VarChar));
    cmd.Parameters["@VendorName"].Value = sVendorName;
    VendorDetails sVendorDetails = null;

    try
    {
        myConnection.Open();
        SqlDataReader dr = cmd.ExecuteReader();
        if (dr.HasRows)
        {
            while (dr.Read())
            {
                sVendorDetails = new VendorDetails();
                sVendorDetails.VendorID = ((int)dr["VendorID"]);
                sVendorDetails.VendorName = ((string)dr["VendorName"]).ToUpper().Trim();
            }
        } 
        else if (dr.HasRows!= true)
        {
            ClientScript.RegisterStartupScript(this.GetType(), "alert", "alert('VendorName:" + sVendorName + " not found. Inserting Vendor details into Vendor and Invoice table.')", true);
            SqlCommand insertcmd = new SqlCommand("dbo.InsertVendorName", myConnection);
            insertcmd.CommandType = CommandType.StoredProcedure;
            insertcmd.Parameters.Add(new SqlParameter("@VendorName", SqlDbType.VarChar));
            insertcmd.Parameters["@VendorName"].Value = sVendorName;
            sVendorDetails = new VendorDetails();
            sVendorDetails.VendorID = insertcmd.ExecuteNonQuery();
            sVendorDetails.VendorName = sVendorName;
        }

        dr.Close(); 
        return sVendorDetails;

        }
        catch (SqlException err)
        {
            throw new ApplicationException("DB usp_GetVendorByVendorName Error: " + err.Message);
        }

        finally
        {
            myConnection.Close();
        }
    }

【问题讨论】:

  • 这就是为什么您应该始终使用using 语句的原因。
  • if (dr.HasRows) { } else if (dr.HasRows!= true) { } 第二个 if 块没有意义。 if (dr.HasRows) { } else { } 做同样的事情。
  • 将连接存储在一个字段中是不好的(如果它是我们不知道的静态连接则更是如此)。而是在您需要的地方创建、打开、使用和关闭连接。最好使用using-statement。
  • 你不能有行,但你仍然打开了 DataReader。进入 Not HasRow if 块时需要关闭它。顺便说一句,将 MultipleActiveResultSets=True; 添加到您的连接字符串将允许在 DataReader 打开时使用连接

标签: c#


【解决方案1】:

您需要在重新使用连接之前关闭/处置您的 DataReader,因为它仍在使用中。

也许是这样的?

var readerHasRows = false;

using (var dr = cmd.ExecuteReader())
{
    readerHasRows = dr.HasRows;

    if(readerHasRows)
    {
        while (dr.Read())
        {
            sVendorDetails = new VendorDetails();
            sVendorDetails.VendorID = ((int)dr["VendorID"]);
            sVendorDetails.VendorName = ((string)dr["VendorName"]).ToUpper().Trim();
        }
    }
}

if(!readerHasRows)
{
    ClientScript.RegisterStartupScript(this.GetType(), "alert", "alert('VendorName:" + sVendorName + " not found. Inserting Vendor details into Vendor and Invoice table.')", true);
    SqlCommand insertcmd = new SqlCommand("dbo.InsertVendorName", myConnection);
    insertcmd.CommandType = CommandType.StoredProcedure;
    insertcmd.Parameters.Add(new SqlParameter("@VendorName", SqlDbType.VarChar));
    insertcmd.Parameters["@VendorName"].Value = sVendorName;
    sVendorDetails = new VendorDetails();
    VendorDetails.VendorID = insertcmd.ExecuteNonQuery();
    sVendorDetails.VendorName = sVendorName;
}

【讨论】:

    【解决方案2】:

    有几点我想说

    1. 您的主要问题是您没有关闭您的DataReader。你可以使用using 声明它
    2. 您无需显式打开和关闭SqlConnectionSqlCommand 对象将根据需要执行此操作。
    3. 您无需检查if (dr.HasRows),然后再次检查while (dr.Read())。此外,您无需循环即可仅获取一行数据。
    4. 理想情况下,我会将“Fetch”部分放在单独的函数中,将“插入”部分放在单独的函数中,这样函数就可以保持小且可重复使用。
    5. 你的模式是多余的if (flag) {TakeAction();} else if (!flag) {TakeAction2();}. Every time the code hits theelse, it will also hit theif (!flag)`
    6. sVendorDetails.VendorID = insertcmd.ExecuteNonQuery(); 行看起来很可疑。如果您的存储过程返回VendorId,那么您应该使用ExecuteScalar。目前它在所有情况下都只是存储1,因为您可能正在插入一行。
    7. 创建自定义ApplicationException 时不要丢弃原始SqlException。上游系统可能想知道比您传递的更多细节。将其作为InnerException 传递
    8. 我还改变了一些风格方面:
      1. 变量名改为更常用的camelCase,而不是错误使用的Hungarian NotationsVendorDetails而不是oVendorDetails
      2. K&R 风格的大括号
      3. 当右侧是new 语句时使用var
      4. 使用对象初始化器而不是创建+赋值

    下面是代码

    public VendorDetails VendorCheck(string vendorName, SqlConnection myConnection) {
        try {
            return GetVendor(vendorName, myConnection) ?? InsertVendor(vendorName, myConnection);
        } catch (SqlException err) {
            throw new ApplicationException("DB usp_GetVendorByVendorName Error: " + err.Message, err);
        }
    }
    
    VendorDetails GetVendor(string vendorName, SqlConnection myConnection) {
        using (var cmd = new SqlCommand("dbo.usp_GetVendorByVendorName", myConnection)) {
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.Parameters.Add(new SqlParameter("@VendorName", SqlDbType.VarChar));
            cmd.Parameters["@VendorName"].Value = vendorName;
    
            using (SqlDataReader dr = cmd.ExecuteReader()) {
                ClientScript.RegisterStartupScript(this.GetType(), "alert", "alert('VendorName:" + vendorName + " not found. Inserting Vendor details into Vendor and Invoice table.')", true); // TODO: Does this really belong here!?!?
                if (dr.Read()) {
                    return new VendorDetails {
                        VendorID = ((int)dr["VendorID"]),
                        VendorName = ((string)dr["VendorName"]).ToUpper().Trim()
                    };
                }
            }
        }
    
        return null;
    }
    
    VendorDetails InsertVendor(string vendorName, SqlConnection myConnection) {
        using (var insertcmd = new SqlCommand("dbo.InsertVendorName", myConnection)) {
            insertcmd.CommandType = CommandType.StoredProcedure;
            insertcmd.Parameters.Add(new SqlParameter("@VendorName", SqlDbType.VarChar));
            insertcmd.Parameters["@VendorName"].Value = vendorName;
            return new VendorDetails {
                VendorID = (int)insertcmd.ExecuteScalar(),
                VendorName = vendorName
            };
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2013-11-26
      • 2022-11-30
      • 2017-08-14
      • 2019-04-09
      • 2021-07-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多