Как передать объекты (байтовый массив) в запрос, если запрос не параметризован?

У меня есть этот запрос для запуска:

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 функция.

Мой вопрос заключается в том, как передать объекты (в моем случае байтовые массивы) в непараметризованных запросах? Если это невозможно, мой вопрос: есть ли альтернатива, чтобы сделать мой запрос быстрее?

2 ответа

Решение

Вот пример (не проверенный просто псевдокод), как я могу представить, что это можно сделать:

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

Ответ Реинуза отвечает на мой вопрос, но в моем случае это болезненно. Когда у меня есть очень большое количество значений для 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;
}

Я конвертирую Guids в его строковое представление и затем передаю его в запрос, где MySQL может выполнить поиск эквивалентной строки.

Для ограниченного числа записей лучше всего подходит параметризованный запрос (ответ Рейнужа). Для очень больших значений, перейти к поиску строки

Изменить: UTF8Encoding нужно использовать здесь, зависит от набора символов базы данных, будь то Unicode и т. д. Я имел успех с .Default в большинстве случаев. Кроме того, строковое представление двоичного файла будет иметь зарезервированные символы. Так что избегай ' или же \

Другие вопросы по тегам