我的id不为空,为什么会收到运行时错误?

3
我收到了这个运行时错误,我的 id 不是 null ,我已经在代码中检查过,你将会看到,并且我正在使用 telerik GridView
以下是运行时错误的内容:

参数化查询 '@_fName nvarchar(4),@_lName nvarchar(2),@_phone nvarchar(6),@_a' 需要提供参数 '@_id',但未提供。

我试图从另一个表单中获取 id,这就是为什么我写成这样的原因。
这是我第一层的代码:
private void btnEdt_Click(object sender, EventArgs e)
{
        Ref_View_Model = new View_model._View_Model();
        Ref_C = new Customers();

        foreach (var RowInfo in Ref_C.radGridView1.SelectedRows)
        {
            FireCell = RowInfo.Cells[0].Value.ToString();

            if (FireCell==null)
            {
                MessageBox.Show("null");
            }
        }

        //Ref_C.radGridView1.CurrentRow.Delete();
        Ref_C.customersTableAdapter.Update(Ref_C.sales_and_Inventory_SystemDataSet);
        Ref_C.customersTableAdapter.Fill(Ref_C.sales_and_Inventory_SystemDataSet.Customers);

        Ref_View_Model.GetEditCustomers(FireCell, txtFName.Text, txtLName.Text, txtPhn.Text, txtDdrss.Text);
} 

这是我在最后一层的代码

public void EditCustomres( string _id,string _fName, string _lName,string _phone, string _address)
{

        Connection_String = @"Data Source=MOSTAFA-PC;Initial Catalog=" + "Sales and Inventory System" + ";Integrated Security=TrueData Source=MOSTAFA-PC;Initial Catalog=" + "Sales and Inventory System" + ";Integrated Security=True;";
        Query = "update Customers " +
                                "set FName=@_fName  ,LName=@_lName  ,Phone=@_phone ,[Address]=@_address" +" "+
                                  "where Id like @_id";
        using (Con=new SqlConnection(Connection_String))
        using (Cmd=new SqlCommand(Query,Con))
        {
            Cmd.Parameters.Add("@_fName", SqlDbType.NVarChar);
            Cmd.Parameters.Add("@_lName", SqlDbType.NVarChar);
            Cmd.Parameters.Add("@_phone", SqlDbType.NVarChar);
            Cmd.Parameters.Add("@_address", SqlDbType.NVarChar);
            Cmd.Parameters.Add("@_id", SqlDbType.Int);

            Con = Cmd.Connection;
            Con.Open();

            Cmd.Parameters["@_fName"].Value = _fName;
            Cmd.Parameters["@_lName"].Value = _lName;
            Cmd.Parameters["@_phone"].Value = _phone;
            Cmd.Parameters["@_address"].Value = _address;
            Cmd.Parameters["@_id"].Value = _id;

            Cmd.ExecuteNonQuery();
            Cmd.Dispose();
            }
} 
2个回答

2

在这种情况下,您真的不想使用LIKE,除非您有非常特定的需求,需要更新看起来像您传递的ID但实际上并不是...

您将@_id作为SqlDbType.Int进行传递,但实际上该变量的类型是string,这将导致在幕后进行转换。如果您传入空字符串,则该值将被转换为null,这将导致您在帖子中提到的错误。检查调用EditCustomres之前的代码,以确保它实际上传递了正确的值。添加参数检查(如我所添加的),将有助于您更早地跟踪这些问题。

第一步是摆脱您的LIKE语句,请更新查询以使用:

where id = @_id

然后更新你的代码,因为你期望_id变量是整数类型,所以不能直接将字符串赋值给它,这可能是为什么它被重置为null的原因。要么更新方法来接受一个int参数而不是string id,要么在添加参数之前在你的方法中解析int

int idValue = -1;
if (!int.TryParse(_id, NumberStyles.Integer, CultureInfo.InvariantCulture, out idValue))
{
    throw new ArgumentException("id", "Id must be a string which contains an integer value, the value of 'id' was: '" + _id + "'"); 
}

Cmd.Parameters.Add("@_id", SqlDbType.Int).Value = idValue;

您可能需要在文件中添加一个using语句:
using System.Globalization;

这是定义NumberStylesCultureInfo的地方。通常情况下,Visual Studio会建议您在哪里找到这些项,按下crtl+.将弹出一个屏幕,自动添加此语句。


最终结果应为:

using System.Globalization;

....
....

public void EditCustomers( string _id,string _fName, string _lName,string _phone, string _address)
{
    int idValue = -1;
    if (!int.TryParse(_id, NumberStyles.Integer, CultureInfo.InvariantCulture, out idValue))
    {
       string message = "Id must be a string which contains an integer value, the value of 'id' was: '" + _id + "'";
       throw new ArgumentException("_id", message); 
    }

    Connection_String = @"Data Source=MOSTAFA-PC;Initial Catalog=" + "Sales and Inventory System" + ";Integrated Security=TrueData Source=MOSTAFA-PC;Initial Catalog=" + "Sales and Inventory System" + ";Integrated Security=True;";
    Query = @"update Customers 
                  set FName=@_fName, LName=@_lName, Phone=@_phone,[Address]=@_address
                  where Id = @_id";

    using (Con=new SqlConnection(Connection_String))
    using (Cmd=new SqlCommand(Query, con))
    {
        Cmd.Parameters.AddWithValue("@_fName", _fName);
        Cmd.Parameters.AddWithValue("@_lName", _lName);
        Cmd.Parameters.AddWithValue("@_phone", _phone);
        Cmd.Parameters.AddWithValue("@_address", _address);
        Cmd.Parameters.AddWithValue("@_id", idValue);

        Con.Open();
        Cmd.ExecuteNonQuery();
    }
}   

我稍微简化了代码。使用原样字符串进行 SQL 语句处理,移除对 Dispose 方法的调用(因为已经通过 using(cmd) 调用),并删除 Con=Cmd.Connection,因为它实际上不能有其他值。
使用 .AddWithValue 方法也比逐个创建并设置值更容易。
非常小心需要在 SQL 服务器端连接字符串来形成 SQL 查询的解决方案, 这可能导致值注入不希望的 SQL 语句,可以将您的数据暴露给外部世界,或者允许外部人员破坏您的数据。
此外,在匹配更新值时要小心使用 LIKE 语句。除非在调用该语句的代码路径中有非常强的参数验证,否则将 id="?"id="%%" 或者只是 id=string.Empty 传递给函数可能会更新所有记录,从而覆盖所有记录以具有相同的值。 %1% 将匹配 1、10、21、31、11、100003...... 这不太可能是期望的行为。
在删除和更新语句中使用 = 而不是 like 几乎总是期望的解决方案。如果使用 = 出现错误,则可能是混合数据类型(例如预期为 intstring)。

你写的异常弹出了,我的代码有什么问题? - Mostafa Bouzari
同时Visual Studio不知道这部分代码NumberStyles.Integer, CultureInfo.InvariantCulture - Mostafa Bouzari
在这种情况下,您可能传递了一个空字符串而不是正在更新的客户的ID,或者它不是一个数字。尝试设置断点并在运行时检查值。NumberStyles和CultureInfo可能需要在文件顶部添加额外的“using System.Globalization;”。 - jessehouwing
已更新答案。并更改异常消息以显示传递的ID。 - jessehouwing

0

你的 idLIKE 子句是不正确的。应该像这样:

Id LIKE '%' + @_id + '%'

或者:

Cmd.Parameters.AddWithValue("@_id","%" + _id+ "%");

或者:

Cmd.Parameters.Add("@_id", SqlDbType.Int).Value = "%" + _id + "%";

虽然最好使用简单的=而不是Like

where Id = @_id

谢谢,它起作用了,但是你能告诉我第一种和第二种解决方案的区别吗?为什么需要这个[%]? - Mostafa Bouzari
@MostafaBouzari... 在第二种方法中,不需要指定SqlDbType。并且对于 like 操作,应该使用 % - Salah Akbari

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接