SqlCommand.Prepare方法要求所有参数都有明确设置的类型。

7

我在我的WCF Web服务中有以下代码片段,根据提供的字典值的格式构建一组where条件。

public static Dictionary<string, string>[] VehicleSearch(Dictionary<string, string> searchParams, int maxResults)
{
    string condition = "";
    foreach (string key in searchParams.Keys)
    {
        //Split out the conditional in case multiple options have been set (i.e. SUB;OLDS;TOY)
        string[] parameters = searchParams[key].Split(';');
        if (parameters.Length == 1)
        {
            //If a single condition (no choice list) check for wildcards and use a LIKE if necessary
            string predicate = parameters[0].Contains('%') ? " AND {0} LIKE @{0}" : " AND {0} = @{0}";
            condition += String.Format(predicate, key);
        }
        else
        {
            //If a choice list, split out query into an IN condition
            condition += string.Format(" AND {0} IN({1})", key, string.Join(", ", parameters));
        }
    }

    SqlCommand cmd = new SqlCommand(String.Format(VEHICLE_QUERY, maxResults, condition));
    foreach (string key in searchParams.Keys)
        cmd.Parameters.AddWithValue("@" + key, searchParams[key]);
    cmd.Prepare();

请注意,字典中的值明确设置为字符串,并且它们是被发送到AddWithValue语句中的唯一项。这将生成类似于以下的SQL代码:
SELECT TOP 200 MVINumber AS MVINumber
    , LicensePlateNumber
    , VIN
    , VehicleYear
    , MakeG
    , ModelG
    , Color
    , Color2
FROM [Vehicle_Description_v]
WHERE 1=1 AND VIN LIKE @VIN

出现错误,报告如下:

System.InvalidOperationException: SqlCommand.Prepare方法要求所有参数都具有明确定义的类型。

我所做的所有搜索都说我需要告诉AddWithValue准备的值的类型,但是我准备的所有值都是字符串,并且我看到的所有示例在处理字符串时没有执行任何额外操作。我错过了什么吗?


为什么要写 1=1?考虑它总是为真,而且你使用了 AND,它总是受 Like @vin 的影响,这意味着 1=1 完全不必要。 - Gonzalo.-
ElVieejo,有时我在代码中构建动态查询时会使用类似 WHERE 1=1 的东西,这样我的其余行就是“AND something”,而不是试图弄清哪一行是第一行并为该行放置 WHERE,然后为其余行放置 AND。 - Jim
EIVieejo,是的,正如Jim所说的那样。我在语句开头使用1=1,以便我只需为每个条件附加“AND”。由于1=1不会真正适用,因此使用它可以使代码保持非常干净。 - taiidani
嘿,我也做同样的“where 1=1”的事情。 - jerrylagrou
2个回答

16

不要这样做:

cmd.Parameters.AddWithValue("@" + key, searchParams[key]);

你需要像这样使用:

cmd.Parameters.Add("@" + key, SqlDbType.******).Value = searchParams[key];

您需要能够以某种方式确定参数的数据类型

这可以是以下内容之一:

  • SqlDbType.Int 用于整数值
  • SqlDbType.VarChar 用于非 Unicode 字符串(不要忘记指定字符串的长度!)
  • SqlDbType.UniqueIdentifier 用于 Guid
    等等。

使用 AddWithValue 很方便,但它让 ADO.NET 根据传入的值猜测数据类型。大多数情况下,这些猜测都相当准确,但有时可能会出现错误。

我建议您始终明确说明要使用的数据类型。


1
那样做需要进行一些小修改。使用SqlDbType代替值产生了相同的错误,我猜测是因为它期望在那个参数中得到一个值。相反地,我将其分配给了一个准备变量,并添加了prep.SqlDbType = SqlDbType.VarChar;,然后还为prep指定了一个Size。 - taiidani
2
为了扩展taiidani的答案,您可以像这样在一行中完成:cmd.Parameters.Add("@PARAM",SqlDbType.TYPE, VALUE.Length).Value = VALUE; - Chris
我相信你想说的是 Add,而不是第二个 AddWithValue @marc_s。否则,人们会感到困惑。 - GSerg
@GSerg:是的,我做到了! :-) 谢谢 - 已修复。 - marc_s

1

如果您阅读文档, 您会发现在使用SQLCommand.Prepare时,需要使用Parameters.Add并为每个参数分配数据类型。该链接中有一个很好的代码示例,可以向您展示如何操作。


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