对象引用未设置为对象的实例 >> 插入查询 c#

object reference not set to an instance of an object >> insert query c#

我有这个方法将数据从文本框和 Datagridview 插入数据库中的两个不同表,第一个插入查询正常执行,但第二个插入查询抛出错误

Object reference not set to an instance of an object

这是我的方法:

private void InsertAll()
{
    DialogResult Result = MessageBox.Show("Do you want to save all ? ", "Warnning", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning);

    if (Result == DialogResult.OK)
    {
        using (SqlCommand cmd = new SqlCommand())
        {
            try
            {
                cmd.Connection = Cn;
                cmd.CommandType = CommandType.Text;

                Cn.Open();

                // Insert the header first Due to one-to-many relationship 
                cmd.CommandText = @" INSERT INTO DocDtls ( DocNum, zDate, Warehouse, Orientation,TransType,UserName )
                                     VALUES (@prm1, @prm2, @prm3, @prm4, @prm5, @prm6);";

                cmd.Parameters.AddWithValue("@prm1", txtDocNum.Text);
                cmd.Parameters.AddWithValue("@prm2", txtDate.Value.ToString("yyyy-MM-dd")); 
                cmd.Parameters.AddWithValue("@prm3", cmbWh.Text);
                cmd.Parameters.AddWithValue("@prm4", txtOrient.Text);
                cmd.Parameters.AddWithValue("@prm5", txtTransType.Text);
                cmd.Parameters.AddWithValue("@prm6", txtUser.Text);

                cmd.ExecuteNonQuery();

                // Insert the Details >> where the problem start to occur
                if (txtTransType.Text == "Release")
                {
                    cmd2.Connection = Cn;
                    cmd2.CommandType = CommandType.Text;

                    // Cn.Open();

                    for (int i = 0; i < DGV1.Rows.Count; i++)
                    {
                        cmd2.CommandText = @"INSERT INTO Transactions ( DocNum, Code, QtyIn, QtyOut, BalanceAfter, Remarks, Unit) 
                                             VALUES (@prm1, @prm2, @prm3, @prm4, @prm5, @prm6,@prm7);";

                        cmd2.Parameters.AddWithValue("@prm1", txtDocNum.Text);
                        cmd2.Parameters.AddWithValue("@prm2", DGV1.Rows[i].Cells["Code"].Value);
                        cmd2.Parameters.AddWithValue("@prm3", 0);
                        cmd2.Parameters.AddWithValue("@prm4", DGV1.Rows[i].Cells["Qty"].Value);
                        cmd2.Parameters.AddWithValue("@prm5", DGV1.Rows[i].Cells["BalanceAfter"].Value);
                        cmd2.Parameters.AddWithValue("@prm6", DGV1.Rows[i].Cells["Remarks"].Value);
                        cmd2.Parameters.AddWithValue("@prm7", DGV1.Rows[i].Cells["Unit"].Value);

                        cmd2.ExecuteNonQuery();

                        MessageBox.Show("Registered", "Done", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    }
                }
                else
                {
                    cmd2.Connection = Cn;
                    cmd2.CommandType = CommandType.Text;

                    //Cn.Open();

                    for (int i = 0; i < DGV1.Rows.Count; i++)
                    {
                        cmd2.CommandText = @"INSERT INTO Transactions ( DocNum, Code, QtyIn, QtyOut, BalanceAfter, Remarks, Unit )
                                             VALUES (@prm1, @prm2, @prm3, @prm4, @prm5, @prm6,@prm7);";

                        cmd2.Parameters.AddWithValue("@prm1", txtDocNum.Text);
                        cmd2.Parameters.AddWithValue("@prm2", DGV1.Rows[i].Cells["Code"].Value);
                        cmd2.Parameters.AddWithValue("@prm3", DGV1.Rows[i].Cells["Qty"].Value);
                        cmd2.Parameters.AddWithValue("@prm4", 0);
                        cmd2.Parameters.AddWithValue("@prm5", DGV1.Rows[i].Cells["BalanceAfter"].Value);
                        cmd2.Parameters.AddWithValue("@prm6", DGV1.Rows[i].Cells["Remarks"].Value);
                        cmd2.Parameters.AddWithValue("@prm7", DGV1.Rows[i].Cells["Unit"].Value);

                        cmd2.ExecuteNonQuery();

                        MessageBox.Show("Registered", "Done", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    }
                }
            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message.ToString(), "Error Message",MessageBoxButtons.OK,MessageBoxIcon.Error);
            }

            Cn.Close();
        }
    }
}

我怀疑连接可能在某个时候关闭,所以我在第一次插入后再次添加打开连接,但问题仍然存在。

我的代码有什么问题?

提前致谢

试试这个。有很多代码,所以可能还有一个错字或其他一两个问题。关注评论:

private void InsertAll()
{    
    using (var cn = new SqlConnection(Cn.ConnectionString)) // Using block around the connection
    using (var cmd = new SqlCommand("", cn))
    {
        //removed the try/catch. Instead, wrap the try/catch around this method call
        
        cmd.CommandText = @" INSERT INTO DocDtls ( DocNum, zDate, Warehouse, Orientation,TransType,UserName )
                                     Values (@prm1, @prm2, @prm3, @prm4, @prm5, @prm6);";
        //AddWithValue() can be dangerously slow, but usually still safe for single simple INSERT
        cmd.Parameters.AddWithValue("@prm1", txtDocNum.Text);
        cmd.Parameters.AddWithValue("@prm2", txtDate.Value); //If you're converting a DateTime to a string for use in SQL, you're doing something VERY WRONG
        cmd.Parameters.AddWithValue("@prm3", cmbWh.Text);
        cmd.Parameters.AddWithValue("@prm4", txtOrient.Text);
        cmd.Parameters.AddWithValue("@prm5", txtTransType.Text);
        cmd.Parameters.AddWithValue("@prm6", txtUser.Text);
        
        cn.Open(); //Wait until last possible moment to call cn.Open()
        cmd.ExecuteNonQuery();

        // Normally don't re-use the same connection, but 
        // within a single operation context like this it's okay
        // not only for the connection, but for the command, too.
        cmd.CommandText = @" INSERT INTO Transactions ( DocNum, Code, QtyIn, QtyOut, BalanceAfter, Remarks, Unit )
                             Values (@DocNum, @Code, @QtyIn, @QtyOut, @BalanceAfter, @Remarks,@Unit);";

        cmd.Parameters.Clear(); //Missing this line is why you had to create cmd2 before.
        // Use exact types from the database here. Don't let ADO.Net try to infer these.
        cmd.Parameters.Add("@DocNum", SqlDbType.VarChar, 10).Value = txtDocNum.Text;
        cmd.Parameters.Add("@Code", SqlDbType.Char, 7);
        // the "= 0" at the end of the next two lines are important.
        cmd.Parameters.Add("@QtyIn", SqlDbType.Int).Value = 0;
        cmd.Parameters.Add("@QtyOut", SqlDbType.Int).Value = 0;
        cmd.Parameters.Add("@BalanceAfter", SqlDbType.Decimal);
        cmd.Parameters.Add("@Remarks", SqlDbType.NVarChar, 1000);
        cmd.Parameters.Add("@Unit", SqlDbType.NVarChar, 10);

        // We can also set the Qty switch outside the loop
        var qtyKey = (txtTransType.Text == "Release")?"@QtyOut":"@QtyIn";

        for (int i = 0; i < DGV1.Rows.Count; i++)
        {
            // Only change parameter values inside the loop           
            cmd.Parameters["@Code"] = DGV1.Rows[i].Cells["Code"].Value;
            cmd.Parameters[qtyKey].Value = DGV1.Rows[i].Cells["Qty"].Value;
            cmd.Parameters["@BalanceAfter"] = DGV1.Rows[i].Cells["BalanceAfter"].Value;
            cmd.Parameters["@Remarks"] = DGV1.Rows[i].Cells["Remarks"].Value;
            cmd.Parameters["@Unit"] = DGV1.Rows[i].Cells["Unit"].Value;

            cmd.ExecuteNonQuery();
       }
       // No need to call cn.Close(). Using blocks take care of it.
    }
}

请注意,我删除了最初的 prompt/check、try/catch 和最后的完整消息。这些东西属于调用者,像这样:

DialogResult Result = MessageBox.Show("Do you want to save all ? ", "Warning", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning);
if (Result == DialogResult.OK) 
{
    try 
    {
        InsertAll()
        MessageBox.Show("Registered", "Done", MessageBoxButtons.OK, MessageBoxIcon.Information);
    }
    catch(Exception e)
    {
        MessageBox.Show(e.Message.ToString(), "Error Message",MessageBoxButtons.OK,MessageBoxIcon.Error);
    }
}

最终,您还将将该方法(和其他数据库访问)移动为 单独 class 的静态成员,其中所需信息作为参数传递。