4

どうやら、ExecuteReader は読み取り専用に使用され、ExecuteNonQuery はトランザクションに使用されます。しかし、何らかの理由で、ExecuteReader を使用した場合でも、書き込み (挿入、更新、削除) コマンド (textbox1 に入力) を実行できます。私のコードに何か問題がありますか、または ExecuteReader が動作するはずの方法を誤解していますか?

//MY CODE

string sqlStatement = textbox1.Text;

System.Data.SqlClient.SqlConnectionStringBuilder builder =
  new System.Data.SqlClient.SqlConnectionStringBuilder();
builder.DataSource = ActiveServer;
builder.IntegratedSecurity = true;

System.Data.SqlClient.SqlConnection Connection = new 
   System.Data.SqlClient.SqlConnection(builder.ConnectionString);
Connection.Open();

System.Data.SqlClient.SqlCommand command = new 
  System.Data.SqlClient.SqlCommand(sqlStatement, Connection);
System.Data.SqlClient.SqlDataReader reader = command.ExecuteReader();

dataGridView1.AutoGenerateColumns = true;

bindingSource1.DataSource = reader;
dataGridView1.DataSource = bindingSource1;

reader.Close();
Connection.Close();
4

3 に答える 3

7

ExecuteReaderSQL プロシージャから返された行を読み取ることができるリーダーを返すだけです。その結果セットを提供する途中で任意の SQL を実行することはできません。

挿入 / 更新 / 削除を実行してからすぐに結果セットを返す (読み取りのように見えるコードから) ことは、間違いなく少し奇妙であり (読み取り: コードの匂い)、個別のアクションに分割できるかどうかを確認する必要があります。

于 2010-07-27T21:11:09.110 に答える
5

どちらもSQLを実行しますが、影響を受けるレコードの数ExecuteReader中にレコードを返すことが期待されExecuteNonQuery ます。したがって、両者は異なります。ただし、内部的には、ベンダー固有の実装によって異なります。(今まで)機能していたのでExecuteReader、すべてのdbアクションに単独で使用できましたが、文書化されていないため、実際には正しいアプローチではありません. を使用すると、意図がより明確になります。ExecuteNonQuery

パフォーマンスを考える限り、私はまったく違いはないと思います。SQLiteMySqlClientSqlClientSqlServerCeおよびで試してみましたが、VistaDbいずれも好ましい違いは見られませんでした。そして、それらはすべて何らかの方法でExecuteReader内部的に使用する必要があります。

必需品:

Sql クライアント:

private int InternalExecuteNonQuery(DbAsyncResult result, string methodName, bool sendToPipe)
{
    if (!this._activeConnection.IsContextConnection)
    {
        if (this.BatchRPCMode || CommandType.Text != this.CommandType || this.GetParameterCount(this._parameters) != 0)
        {
            Bid.Trace("<sc.SqlCommand.ExecuteNonQuery|INFO> %d#, Command executed as RPC.\n", this.ObjectID);
            SqlDataReader sqlDataReader = this.RunExecuteReader(CommandBehavior.Default, RunBehavior.UntilDone, false, methodName, result);
            if (sqlDataReader == null)
            {
                goto IL_E5;
            }
            sqlDataReader.Close();
            goto IL_E5;
        }
    IL_B5:
        this.RunExecuteNonQueryTds(methodName, flag);
    }
    else
    {
        this.RunExecuteNonQuerySmi(sendToPipe);
    }
IL_E5:
    return this._rowsAffected;
}

MySql クライアント:

public override int ExecuteNonQuery()
{
  int records = -1;

  #if !CF
  // give our interceptors a shot at it first
  if ( connection != null && 
       connection.commandInterceptor != null &&
       connection.commandInterceptor.ExecuteNonQuery(CommandText, ref records))
    return records;
  #endif

  // ok, none of our interceptors handled this so we default
  using (MySqlDataReader reader = ExecuteReader())
  {
    reader.Close();
    return reader.RecordsAffected;
  }
}

MySqlClientあなたが直接見ることができるように、呼び出しは特定の条件に対してのみ行われますExecuteReaderss がボトルネックになることはめったにないことに注意してください (多くの場合s です)。SqlClientinsertupdateselect

私が言ったように、 の助けを借りても影響を受ける行数は得られないので、より良いクエリをExecuteReader使用ExecuteNonQueryしてください。より直接的な置き換えExecuteReaderExecuteScalar、最初に読み取った行の最初の列のデータを返すものです。

必需品:

Sql クライアント:

override public object ExecuteScalar()
{
    SqlConnection.ExecutePermission.Demand();

    // Reset _pendingCancel upon entry into any Execute - used to synchronize state
    // between entry into Execute* API and the thread obtaining the stateObject. 
    _pendingCancel = false;

    SqlStatistics statistics = null;
    IntPtr hscp;
    Bid.ScopeEnter(out hscp, "<sc.sqlcommand.executescalar|api> %d#", ObjectID);
    try
    {
        statistics = SqlStatistics.StartTimer(Statistics);
        SqlDataReader ds = RunExecuteReader(0, RunBehavior.ReturnImmediately, true, ADP.ExecuteScalar);

        object retResult = null;
        try
        {
            if (ds.Read())
            {
                if (ds.FieldCount > 0)
                {
                    retResult = ds.GetValue(0);
                }
            }
            return retResult;
        }
        finally
        {
            // clean off the wire 
            ds.Close();
        }
    }
    finally
    {
        SqlStatistics.StopTimer(statistics);
        Bid.ScopeLeave(ref hscp);
    }
}

MySql クライアント:

public override object ExecuteScalar()
{
    lastInsertedId = -1;
    object val = null;

    #if !CF
    // give our interceptors a shot at it first
    if (connection != null &&
        connection.commandInterceptor.ExecuteScalar(CommandText, ref val))
        return val;
    #endif

    using (MySqlDataReader reader = ExecuteReader())
    {
        if (reader.Read())
            val = reader.GetValue(0);
    }

    return val;
}

したがって、ExecuteReaderforを使用しても問題はExecuteScalarなく、パフォーマンスの違いはまったくありません..

于 2013-02-19T12:14:32.423 に答える
3

これらのメソッドの基礎となる実装は、指定された SQL ステートメントを実行するだけなので、これらのメソッドのいずれかを使用してほとんどすべてのステートメントを実行できます。最終結果は、リーダーが期待される結果セットを返そうとするのに対し、他のメソッドは結果セットを期待しないということです。結果セットを生成しないステートメントを実行するために ExecuteReader を使用するのは、おそらく少し効率的ではありません。プロバイダーは引き続きデータ リーダー オブジェクトを作成しますが、これには少しコストがかかります (プロバイダーがサーバーに対して別の往復呼び出しを行わない限り、ほとんどの場合、おそらく無視できる程度です)。

于 2010-07-27T21:11:53.320 に答える