【问题标题】:OleDbCommand with 'where in' and dbParameter带有 'where in' 和 dbParameter 的 OleDbCommand
【发布时间】:2019-01-07 10:53:24
【问题描述】:

我尝试通过 C# 从 access 数据库文件中的表中删除一些行。 此尝试失败且没有错误,这使我得出结论,我有一个包含不正确数据的有效查询。

我尝试查看是否可以使用代码中的 select 语句查询数据,我可以将问题缩小到参数。

语句应该如下所示

SELECT * FROM tbIndex where pguid in ('4a651816-e15b-4c6a-85c4-74033ca6c423', '0add7bff-a22f-4238-9c7f-e1ff4ed3c7e2', '742fae8b-2692-4a6f-802c-848fad570696', '5e6b65de-2403-4800-a47d-e57c7bd8e0a6')

我尝试了两种不同的方法*(dbCmd2 和 dbCmd3)*,第一种方法*(dbCmd2)* 工作,但由于注入问题,这不是我喜欢的解决方案。

using (OleDbCommand dbCmd2 = new OleDbCommand { Connection = m_Connection })
{
    dbCmd2.CommandText = "SELECT * FROM tbIndex where pguid in ("+pguid+")";
    using (DbDataReader reader = dbCmd2.ExecuteReader())
    {
        List<object[]> readValuesFromIndex = new List<object[]>();
        while (reader.Read())
        {
            //Point reached
            object[] arr = new object[reader.VisibleFieldCount];
            reader.GetValues(arr);
            //...
        }
        reader.Close();
    }

    using (OleDbCommand dbCmd3 = new OleDbCommand { Connection = m_Connection })
    {
        dbCmd3.CommandText = "SELECT * FROM tbIndex where pguid in (@pguid)";
        dbCmd3.Parameters.Add("@pguid", OleDbType.VarChar).Value = pguid;
        using (DbDataReader reader = dbCmd3.ExecuteReader())
        {
            List<object[]> readValuesFromIndex = new List<object[]>();
            while (reader.Read())
            {
                //Point not reached
                object[] arr = new object[reader.VisibleFieldCount];
                reader.GetValues(arr);
                //...
            }
            reader.Close();
        }
    }

请注意,pguid 设置为 "'4a651816-e15b-4c6a-85c4-74033ca6c423', '0add7bff-a22f-4238-9c7f-e1ff4ed3c7e2', '742fae8b-2692-4a6f-802c-848fad570696', '5e6b65de-2403-4800-a47d-e57c7bd8e0a6'"

我一直认为第二个选项会以安全的方式简单地替换参数,但显然不是这样。

我的问题是: 为什么第二个选项不返回任何值?

【问题讨论】:

  • 第一个查询对 SQL 注入开放,因此不得使用。几乎可以肯定,第二种方法行不通。
  • PetaPoco 和其他 ORM 支持内置的 IN 子句 (redeyedmonster.co.uk/petapoco-documentation - When using a WHERE IN clause)。您是否考虑过这里的一个选项?
  • 认为你要求的是服务器匹配'4a651816-e15b-4c6a-85c4-74033ca6c423', '0add7bff-a22f-4238-9c7f-e1ff4ed3c7e2', '742fae8b-2692-4a6f-802c-848fad570696', '5e6b65de-2403-4800-a47d-e57c7bd8e0a6'中的任何条目但是你实际上问它是匹配任何一组条目。 唉,该集合中的一个(也是唯一一个)条目'4a651816-e15b-4c6a-85c4-74033ca6c423', '0add7bff-a22f-4238-9c7f-e1ff4ed3c7e2', '742fae8b-2692-4a6f-802c-848fad570696', '5e6b65de-2403-4800-a47d-e57c7bd8e0a6'(注意这是一个单个字符串,而不是四个字符串)。
  • 所以,你不需要像你正在做的那样传递一个参数。您需要传递 四个 参数(每个字符串一个)。 PetaPoco 和其他 ORM 会自动为您执行此操作。

标签: c# sql ms-access oledbcommand


【解决方案1】:

参数始终是一个单个值。

in 子句需要多个值,以逗号分隔。

您可以执行以下操作来像单独的参数一样传递它们:

string[] guids = pguid.Split(',');
string sqlin = "";
int paramno = -1;
foreach (var guid in guids)
{
   parametercount ++;
   sqlin = sqlin + "@Param" + (string)parametercount; + ","
}
dbCmd3.CommandText = "SELECT * FROM tbIndex where pguid in (" + sqlin.Substring(0, sqlin.Length-1) + ")";
for(int i = 0; i <= parametercount; i++){
    dbCmd3.Parameters.Add("@Param" + (string)i, OleDbType.VarChar).Value = guids[i].Replace("'", "");
}

【讨论】:

  • 还可以考虑使用Enumerable.Rangestring.Join 以避免需要遍历guids 来生成params
  • 谢谢。你的答案是对的,所以+1。由于@mjwills 首先在 cmets 中写了答案,我会将他的答案标记为已接受的答案,如果 mjwills 没有写答案,我会将其设为已接受的答案。
猜你喜欢
  • 2020-11-11
  • 1970-01-01
  • 2014-05-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-21
  • 1970-01-01
  • 2011-01-23
相关资源
最近更新 更多