【问题标题】:how to pass objects (byte array) in query if query is not parameterized?如果查询未参数化,如何在查询中传递对象(字节数组)?
【发布时间】:2012-04-17 11:47:55
【问题描述】:

我要运行这个查询:

string query = @"SELECT *
                 FROM   hint 
                 WHERE  addedSessionId IN (x, y, z, ............)";


if (_connSource.State != ConnectionState.Open)
    _connSource.Open();

MySqlCommand cmd = new MySqlCommand(query, _connSource);
MySqlDataReader r = cmd.ExecuteReader();

List<Hint> lstHint = new List<Hint>();
while (r.Read())
{
    Hint h = new Hint(Convert.ToInt32(r[0]), Convert.ToInt32(r[1]), 
                      Convert.ToString(r[2]), Convert.ToInt32(r[3]), 
                      Convert.ToInt32(r[4]));
    h.addedSessionId = (Guid)r[5];

    lstHint.Add(h);
}

r.Close(); //important

在上面的代码中,如何将值x, y, z etc 传递给查询本身? x, y, z etc 不是 int 或 string 而是字节数组。在我的代码中,它们是 .net Guid 字段,但我通过将其转换为字节数组将其作为二进制值保存在 db 中。

我可以通过如下所示的参数化方式来实现我想要的:

string query = @"SELECT *
                 FROM   hint 
                 WHERE  addedSessionId = @newSessionId";


if (_connSource.State != ConnectionState.Open)
    _connSource.Open();

List<Hint> lstHint = new List<Hint>();
foreach (List<Guid> myGuid in lstGuid)
{
    MySqlCommand cmd = new MySqlCommand(query, _connSource);
    cmd.Parameters.AddWithValue("newSessionId", myGuid.ToByteArray());
    MySqlDataReader r = cmd.ExecuteReader();

    while (r.Read())
    {
        int id = Convert.ToInt32(r[0]);

        if (IsThisEntryAlreadyAdded(id, lstHint))
            continue;

        Hint h = new Hint(id, Convert.ToInt32(r[1]),
                          Convert.ToString(r[2]), Convert.ToInt32(r[3]),
                          Convert.ToInt32(r[4]));
        h.addedSessionId = (Guid)r[5];

        lstHint.Add(h);
    }

    r.Close(); //important
}

第二种方法的问题是它相对慢得多。这里不仅查询必须多次运行到数据库,而且每次我都需要通过运行IsThisEntryAlreadyAdded 函数来确保该特定条目是否尚未添加。

我的问题是如何在非参数化查询中传递对象(在我的情况下是字节数组)?如果不可能,我的问题是有没有其他方法可以让我的查询更快?

【问题讨论】:

  • 您可以同时构建查询和使用参数
  • @Reniuz 真是个好主意。不是我没有想过,而是如何实现?我可以看到一些示例代码?
  • 我在答案代码示例中添加了。

标签: c# mysql binary .net-2.0 parameterized-query


【解决方案1】:

这里是示例(未测试只是伪代码)我想如何做到这一点:

string query = @"SELECT * FROM   hint  WHERE  addedSessionId IN (";
MySqlCommand cmd = new MySqlCommand(query, _connSource);
int i = 0;
foreach (List<Guid> myGuid in lstGuid)
{
    query = string.Format("{0}@param{1}", query, i);
    cmd.Parameters.AddWithValue(string.Format("@param{0}", i), myGuid.ToByteArray());
    i++;
    if(i != lstGuid.Count) query = string.Format("{0},", query);
}
query = string.Format("{0})", query);
cmd.CommandText = query;
//Here you have command with constructed query and params

【讨论】:

  • 太棒了,这正是我的想法。但没想到这个"@param"+i.ToString(); 部分会这么傻。我并没有太在意,而是很想知道这种情况下的标准做法。在这种情况下,这是公认的做法吗?
  • 好吧,我看不出这里有什么问题......也许你可以在这个地方更改为 myGuid.ToString 来制作“不可预测”参数:)
  • 哈哈,很好。谢谢。不能继续使用 tostring,因为在我的数据库中,Guid 字段是 Guid 的二进制表示,而不是 char 表示。最后,无论如何,谢谢...
【解决方案2】:

@Reinuz 的回答回答了我的问题,但在我的情况下它很痛苦。当IN ( 子句的值非常多时,我可以超过允许的最大数据包大小,因此查询根本不会运行。

这就是我最终得到的结果,对于大桌子要快得多:

string query = @"SELECT * 
                 FROM   hint 
                 WHERE  addedSessionId IN (" + GetStringValuesFromGuidList()  + ")";

void GetStringValuesFromGuidList()
{
    string guids = null;
    for (int i = 0; i < lstGuid.Count; i++)
    {
        guids += "'" + UTF8Encoding.Default.GetString(lstGuid[i].ToByteArray()).Replace("\\", "\\\\").Replace("'", "''") + "'";
        if (i < lstGuid.Count - 1)
            guids += ", ";
    }

    return guids;
}

我将 Guid 转换为其字符串表示形式,然后将其传递给 MySQL 可以在哪里进行等效字符串搜索的查询。

对于有限数量的条目,参数化查询(Reinuz 的答案)是最好的。对于非常大的值,请使用字符串搜索

编辑:这里应该使用的UTF8Encoding 取决于数据库的字符集,是否它的unicode 等。在大多数情况下,我使用.Default 取得了成功。此外,二进制的字符串表示将具有保留字符。所以用'\ 逃避它

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-10-20
    • 1970-01-01
    • 2013-04-02
    • 2020-10-31
    • 2014-04-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多