2011-12-15 6 views
7

ルック:C#:Readerに要素が1つしかない場合、 "while"ではなく "if"を使用する必要がありますか?この時

myReader = cmd.ExecuteReader(); 
if (myReader.HasRows) 
{ 
    while (myReader.Read()) 
    { 
     info = myReader.GetString("info"); 
     ... 
    } 
} 
..... 

まあ、私はなぜ知っているドントが、私はそれをコンパイルし、別のPCで使用する場合ながら、それが理由の爆発します。しかし、私がすれば:

myReader = cmd.ExecuteReader(); 
if (myReader.HasRows) 
{ 
    if (myReader.Read()) <------------------- NOTICE THE IF 
    { 
     info = myReader.GetString("info"); 
     ... 
    } 
} 
..... 

...うまくいきます。私は私が原因でプログラムのロジックで、一つだけの要素すべての時間を持っていることがわかっていることに注意してください。

これを行うにはOKですか?それは恐ろしく見え、おそらく良い練習ではありません()。私はあなたのオリエンテーションを求めています。

EDIT:私のエラーを見つけるのに役立つ可能性があるため は、いくつかのより多くのコードを掲載します:

while (myReader.Read()) 
{ 
    info = myReader.GetString("info"); 
    ... 


    /** 
     * Write the relevant info in the LOGS 
     */ 
     connection.Close();  <---------- :S 
     connection.Open();  <---------- if I don´t do this I got some problems with the connection!!!! 
     string queryLog = "INSERT INTO ....; 
     MySqlCommand cmdLog = new MySqlCommand(queryLog, connection); 
     cmdLog.ExecuteNonQuery(); 
} 
+5

「爆発」とはどういう意味ですか? – SLaks

+0

あなたが持っているのと同じように避けるのではなく、おそらく理解すべき根本的な問題があるようです。爆発は何を意味しますか?例外がスローされますか?どのような例外ですか? –

+0

例外です - 私は今すぐ手元にありませんが、接続についてです。私はそれについていくつかのコードを追加するために投稿を編集しました。 – Kani

答えて

13

私は期待していたときに私はこれを行うだけで1行、それと間違って何もありません。

私は単一の値を期待していた場合、私の代わりにExecuteScalarを使用しています。これは、返される結果セットの最初の行の最初の列に保持されている値を単に返します。通常、セットには1つの列と1つの行しかありません。

はまた、私はこれをカバーif (myReader.HasRows)if (myReader.Read())ように気にしない傾向があります。

なぜwhileが問題を引き起こすのかわかりません。複数行が必要でない場合は、whileよりifを使用すると私の意見を提供しています。

+0

今のところ、私はExecuteScalarが文字列を返すことを認識しませんでした。私はいつもスカラーを数値と考えていました。物理学と数学で一般的に使われていて、ExecuteScalarが最も頻繁にカウントを返すためです。 @EricJ。 –

+0

ええ、このメソッドの命名はまったく幻想的ではありませんが、個人的には私がスカラーを「単一の値」として読んでいるので、今まであなたの視点を考慮したことはありません:-) –

+0

"スカラー"これはリストではなく「単一要素」を意味すると理解しています。 – recursive

3

whileを使用しなければ、読者はあなたがそれを持ってすべきだと思うよりも多くの要素を持っている予期しない状態を検出することはできません。システムは時間の経過と共に変化し、システムが進化するにつれて、「読者はたった一つの要素しか持たない」というような前提が不正確になる傾向があります。

システムの機能や、あなたが書いているコードの機能に重要なことがある場合は、私はまだwhileを使用し、実際には1つの要素のみを受け取りました。

+0

良い点ですが、Ifの代わりにWhileを使用するのは本当に傷つきません。この分野で私が認識しているパフォーマンスの問題はありません –

+0

ありがとうございます。私はシステムが変わるかもしれないとあなたが正しいと信じています。私は私の大学と話をする必要があります参照する必要があります変更**、** ** – Kani

3

私はifの使用は、あなたが正確に1つのアイテムを期待して、コードの読者にそれが明確に考えます。あなたはこのように、論理エラーをキャッチするために終了した後にアサートを追加することができます。

if (myReader.Read()) { 
    info = myReader.GetString("info"); 
    ... 
} 
Debug.Assert(!myReader.Read(), "Reader has more elements than expected."); 
+0

+1アサーションの良い呼び出し。 –

-5

をこのコードあなたはそれが行

myReader = cmd.ExecuteReader(); 
    myReader.Read(); 
    if (myReader.HasRows) 
    {  
    while (myReader.Read()) 
    { 
     info = myReader.GetString("info"); 
    } 
    } 
+5

そのコードはそれほど素晴らしいものではありません。読者が読んでから最初の戻り値が見つからないようにする前に読者を繰り返します。 OPは1行にしか興味がないので、実際には十分ではありません。 –

+0

私は理解している..私は彼が何をすることができるかを彼に示していた。使用することを理解するのは彼の責任である。彼のコードから読んで、1列または多くを返すかどうかは分からない。投票は少し時期尚早です。 – MethodMan

+8

downvoteは返されたすべての結果セットの最初の行をスキップしていても、複数の行であっても私の意見では保証されました - 私は野生でこれが必要であるとは見たことがなく、デバッグするのは面倒です。 OPはまた、彼は "ただ一つの要素"を期待していると述べている。彼は既に彼が持っているコードを表示しているので、潜在的なバグ以外にどのような価値が追加されているのか分かりません。 –

0

を返し返したりしないように取得するために以下を追加する必要があり、私はあなたがすべきだと思いますあなたはそれを呼び出すときに単一の行の期待を表現するためにlinqを使用している場合でも、あなたは1つの行だけを期待している間も、まだwhileを使用します。あなたはこれをうまく表現するためにコルーチンを使うことができます。

public IEnumerable<string> GetInfo() 
{ 
    // make command and reader... 
    while(reader.Read() 
    { 
     yield return reader.GetString("info"); 
    } 
} 

呼び出し元は、単一行の期待値を表現するためにSingle()メソッドを使用する必要があります。

var info = GetInfo().Single(); 
1

あなたの接続とリーダーを正しく処分しますか?同様に、Usingを使用します。

using (myReader = cmd.ExecuteReader()) 
{ 
    if (myReader.HasRows) 
    { 
     while (myReader.Read()) 
     { 
      info = myReader.GetString("info"); 
      ... 
     } 
    } 
} 
3

あなたは確かにifを使用することができますが、エラーなしで、このような場合にはwhileを使用することができるはずです。 ifに変更するだけですが、複数の行を持つことができる場合に同じことをすると、同じエラーが発生します。したがって、例外が発生した理由を調べることが重要です。

のは、あなたのコードを見てみましょう:

while (myReader.Read()) 
{ 
    info = myReader.GetString("info"); 
    ... 

をこれまでのところは良いです。

 /** 
     * Write the relevant info in the LOGS 
     */ 
     connection.Close();  <---------- :S 
     connection.Open();  <---------- if I don´t do this I got some problems with the connection!!!! 

ああ!あなたはあなたの "いくつかの問題"を修正しましたが、あなたはそれらの "いくつかの問題"が何であったか知っていましたか?実際には、あなたがwhileを壊したことがあります。私は、「これまでのところは良い」と述べた時点で

が、これはあなたが起こっているものです:

  1. あなたは接続オブジェクトを持っています。それが開いています"。
  2. データリーダーオブジェクトがあります。接続からデータを取得しています。

IDbCommand.ExecuteReader(http://msdn.microsoft.com/en-us/library/68etdec0.aspx)の仕様では、この接続はそのリーダーで使用されています。明示的に、またはusingブロックに割り当てられた場合にはDispose()によって、Close()を読者に呼び出すまで、接続を閉じる以外は何もすることはできません。

厳密には、これは必ずしも真実ではありません。特定の実装では、インターフェイスの約束以上(インターフェイスの署名に従って、またはドキュメントに従って)、常にあなたに与えることが許可されています。多くの実装では、Read()がfalseを返すと接続を「解放」します(SQLServer 2005にはMultipleActiveResultSets=Trueオプションがあります)。これにより、同じ接続で同時に複数のデータエリアを同時にサポートできます(欠点があります)。それでも、規則のこれらの緩みは、私たちが現在の接続で間違いなく行うことができるのはClose()です。

この理由から、cmdLog.ExecuteNonQuery()を呼び出そうとすると、エラーメッセージの形で「何らかの問題」が発生しました。これは、使用中の接続を使用しようとしたためです。

このように、接続で行うことができた唯一のことを行うことで、これを「固定」してから、もう一度開きます。すべての目的と目的のために、あなたは真新しいつながりを持っています!

でも、whileにループバックすると、myReader.Read()が再び呼び出されます。このメソッドは、接続からのデータストリームを読み込み、falseが返された場合(結果がない場合)、またはストリームから読み込んだ内容に基づいて一連のフィールドを作成します。

しかし、あなたはその接続をクローズしています。つまり、クローズド接続から読み込みしようとしているだけで、実行できないため、例外が発生します。

whileifに変更すると、Read()操作に戻ったことはないので、コードは再び機能します。

しかし、複数の行を持つ結果セットでこれを行う必要がある場合はどうしますか?

MARSを使用できます。それについてはhttp://msdn.microsoft.com/en-us/library/h32h3abf%28v=vs.80%29.aspxを参照してください。率直に言って、何かがそれ以上のものを得ない限り、私はそれを避けるだろう。それはあなたがそれらをヒットすると本当に混乱することができるいくつかの微妙な含意があります。

読者セットが閉じられるまで、次の操作を延期することができます。この場合、これは単に不必要Open()Close()取り出すことによりマイナー省のようになります。

using(myReader = cmd.ExecuteReader()) 
{ 
    while(myReader.Read()) 
    { 
    string info = myReader.GetString("info"); 
    /* Do stuff */ 
    using(SqlConnection logConn = new SqlConnection(...)) 
    { 
     logConn.Open(); 
     string queryLog = "INSERT INTO ....; 
     MySqlCommand cmdLog = new MySqlCommand(queryLog, connection); 
     cmdLog.ExecuteNonQuery(); 
    } 
    } 
} 

を、2つの接続ではなく、ここでは1を持っている無駄に見えるかもしれません。ただし:

  1. プールすると接続がかなり安くなります。
  2. ExecuteNonQuery()を実行するとすぐにプールに戻しますので、多くのスレッドでこのようなことが起こっていると、外出先での接続の総数は2倍になりますスレッド。一方、これを実行するスレッドが1つしかない場合は、余分な接続が1つしかないので、誰が気にします。
  3. datareaderを提供する途中で接続を終了すると、プールに戻る前に余分なクリーンアップが行われている可能性があります。したがって、2つの接続を使用している可能性があります(SQLServer、そのような場合にプールに戻る前に、より多くの作業が必要なデータベースもあることはわかっています)。

要約すると、再利用せずに接続を使用することはできません。それは出てくるバグです。通常は、一度に同じ接続で複数の操作を行うことはできません。 SQLServer2005でMultipleActiveResultSetsオプションを使用すると、複雑になりますが、これを行うことができます。一般に、一度に複数のDBを処理する場合は、複数の接続を使用する必要があります。

あなたはまだif ISNいくつかの時間が戻ってくるifではなくwhileを使用しますが、それを行うことが一度に理にかなっているものだから、というよりも、あなたがそれを理解していないバグを修正することができ、言ったすべてのオプションです。

+0

素晴らしい!ありがとうございました。 – Kani

関連する問題