2012-04-17 1 views
0

私はこのクエリを実行する必要があります。上記のコードでクエリがパラメータ化されていない場合、クエリでオブジェクト(バイト配列)を渡す方法は?

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関数を実行して追加されていないかどうかを確認する必要があるたびに、クエリを実行する必要があります。

私の質問は、どのように(私の場合はバイト配列)非パラメータ化クエリで渡すか?その不可能な場合、私の質問は、私のクエリをより速くするための代替ですか?

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 
+1

でエスケープすると、クエリを作成して同時にパラメータを使用することができます。 – Reniuz

+0

@ Reeniuz thats素晴らしいアイデアです。それについては考えていませんが、実装する方法は?私が見ることができるいくつかのサンプルコードですか? – nawfal

+0

回答コードサンプルに追加しました。 – Reniuz

答えて

1

は、私はこれを行うことができる想像どのように(ちょうど擬似コードをテストしていません)のサンプルです。 IN (句の値が非常に多い場合、許容される最大パケットサイズを超えることができ、したがってクエリはまったく実行されません。私は、MySQLは、同等の操作を行うことができる場所照会に渡し、その文字列表現にGUIDを変換し、

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; 
} 

:だからここ

は、私は大きなテーブルためはるかに高速である、になってしまったものです文字列検索。

エントリの数が限られている場合は、パラメータ化されたクエリ(Reinuzの答え)が最適です。非常に大きな値の場合、文字列検索のために行く

編集:UTF8Encoding 1は、ここで使用する必要がありますが、私はほとんどの場合、.Defaultで成功を収めてそのユニコードなどかどうかをデータベースの文字セットに依存します。さらに、バイナリの文字列表現には予約文字があります。 'または\

+0

これはまさに私の心にあったものです。しかし、この '' @param "+ i.ToString();'の部分は愚かであるとは思わなかった。私はそれにあまりにも多くの心を入れていない代わりにそのようなシナリオで標準的な練習を知って好奇心があった。このような場合、これは容認された慣行ですか? – nawfal

+0

私はここで何か間違っていることを見ることはできません...多分あなたは '予測不可能な'パラメータを作るためにこの場所でmyGuid.ToStringに変更することができます:) – Reniuz

+0

ハハ、罰金。ありがとう。私のdbではGuidフィールドはGuidsのバイナリ表現であり、char表現ではないので、tostringを使うことはできません。最後に、とにかく感謝... – nawfal

1

Reinuzの答えは私の質問に答える@が、私のシナリオでその痛みを伴う:ここ

関連する問題