2

SQLでCCRを実装する際に問題が発生しました。コードをステップスルーすると、更新と挿入をうまく実行しようとしているようです。しかし、ブレークポイントなしでインターフェイスを実行すると、動作しているように見え、挿入、更新が表示されますが、実行の最後に、データベースに何も更新されませんでした。

プールから新しいスレッドをプルするたびにコードに一時停止を追加しましたが、それは機能します...しかし、それは非同期コーディングの目的を無効にしますか?インターフェースを遅くするのではなく、速くしたい...

任意の提案...ここに私のコードの一部があります:

2つのヘルパークラスを使用してポートを設定し、応答を返します...

    /// <summary> 
    /// Gets the Reader, requires connection to be managed 
    /// </summary> 
    public static PortSet<Int32, Exception> GetReader(SqlCommand sqlCommand)
    {
        Port<Int32> portResponse = null;
        Port<Exception> portException = null;
        GetReaderResponse(sqlCommand, ref portResponse, ref portException);
        return new PortSet<Int32, Exception>(portResponse, portException);
    }

    // Wrapper for SqlCommand's GetResponse 
    public static void GetReaderResponse(SqlCommand sqlCom,
       ref Port<Int32> portResponse, ref Port<Exception> portException)
    {
        EnsurePortsExist(ref portResponse, ref portException);
        sqlCom.BeginExecuteNonQuery(ApmResultToCcrResultFactory.Create(
           portResponse, portException,
           delegate(IAsyncResult ar) { return sqlCom.EndExecuteNonQuery(ar); }), null);
    }

それから私は私の呼び出しをキューに入れるためにこのようなことをします...

        DispatcherQueue queue = CreateDispatcher();
        String[] commands = new String[2];
        Int32 result = 0;
        commands[0] = "exec someupdateStoredProcedure";
        commands[1] = "exec someInsertStoredProcedure '" + Settings.Default.RunDate.ToString() + "'";

        for (Int32 i = 0; i < commands.Length; i++)
        {
            using (SqlConnection connSP = new SqlConnection(Settings.Default.nbfConn + ";MultipleActiveResultSets=true;Async=true"))
            using (SqlCommand cmdSP = new SqlCommand())
            {
                connSP.Open();
                cmdSP.Connection = connSP;
                cmdSP.CommandTimeout = 150;
                cmdSP.CommandText = "set arithabort on; " + commands[i];

                Arbiter.Activate(queue, Arbiter.Choice(ApmToCcrAdapters.GetReader(cmdSP),
                    delegate(Int32 reader) { result = reader; },
                    delegate(Exception e) { result = 0; throw new Exception(e.Message); }));
            }
        }

ここで、ApmToCcrAdaptersは、ヘルパーメソッドが存在するクラス名です...

問題は、Arbiter.Activateを呼び出した直後にコードを一時停止し、データベースをチェックすると、すべてが正常に見えることです...一時停止広告を削除すると、コードが実行され、データベースには何も起こらず、例外もありませんどちらかがスローされます...

4

1 に答える 1

3

ここでの問題は、2 つのブロックArbiter.Activateのスコープで呼び出していることです。作成した CCR タスクがキューに入れられ、現在のスレッドがブロックusingのスコープを超えて継続することを忘れないでください。デバッグ時に観察したように、スレッドのタイミングに干渉している場合にのみ発生する必要がusingあるため、競合状態が発生しました。ChoiceconnSPcmdSP

代わりに、 のハンドラー デリゲートで手動で破棄を処理する場合Choice、この問題は発生しなくなりますが、これにより、破棄を見落としやすい脆弱なコードが作成されます。

ステートメントMulitpleItemReceiveを保持できるように、CCR イテレータ パターンを実装し、 a で結果を収集することをお勧めします。usingよりクリーンなコードになります。私の頭の上からは、次のようになります。

private IEnumerator<ITask> QueryIterator(
    string command,
    PortSet<Int32,Exception> resultPort)
{
    using (SqlConnection connSP = 
        new SqlConnection(Settings.Default.nbfConn 
            + ";MultipleActiveResultSets=true;Async=true"))
    using (SqlCommand cmdSP = new SqlCommand())
    {
        Int32 result = 0;
        connSP.Open();
        cmdSP.Connection = connSP;
        cmdSP.CommandTimeout = 150;
        cmdSP.CommandText = "set arithabort on; " + commands[i];

        yield return Arbiter.Choice(ApmToCcrAdapters.GetReader(cmdSP),
            delegate(Int32 reader) { resultPort.Post(reader); },
            delegate(Exception e) { resultPort.Post(e); });
    }

}

次のように使用できます。

var resultPort=new PortSet<Int32,Exception>();
foreach(var command in commands)
{
    Arbiter.Activate(queue,
        Arbiter.FromIteratorHandler(()=>QueryIterator(command,resultPort))
    );
}
Arbiter.Activate(queue,
    Arbiter.MultipleItemReceive(
        resultPort,
        commands.Count(),
        (results,exceptions)=>{
            //everything is done and you've got 2 
            //collections here, results and exceptions
            //to process as you want
        }
    )
);
于 2010-12-01T20:15:00.840 に答える