3

enter code here Webappでは、異なるSQLサーバー上に全く同じテーブルスキーマを持つデータベースのインスタンスが5つあります。 これらの5つのデータベース/サーバーすべてに対してObjectcontextで使用可能なExecuteStoreQuery()メソッドを使用してSQLクエリ(またはクエリ)を並列に実行し、マージ結果を返したいとします。私は重複を気にしないので、すべてのDBのすべての結果のUNIONが私のために働くでしょう。複数のデータベースでSQLクエリを並列に実行し、ADO.NET Entity Frameworkを使用して結合結果を返す方法

私の最初の考えは、これらの5つのDBすべてにweb.configファイルと自分のコードで保存し、それぞれの接続文字列を渡し、接続文字列をparamとしてインスタンス化してからBackGroundWorkerを使用して接続文字列ごとに1つのスレッドをスピンオフし、すべてのDBに対して同じクエリを並列に実行します。各スレッドで1回実行し、最後にすべてのスレッドの結果セットを結合します。

これはうまくいくはずですが、これを解決するより良い方法があるのか​​、EFにスレッドで並列実行することでこれを行うことができるinbuiltメソッドがあるのだろうかと思います。

UPDATE

/// <summary> 
    /// Executes a store query in parallel on all the DB servers 
    /// </summary> 
    /// <typeparam name="TElement"></typeparam> 
    /// <param name="commandText"></param> 
    /// <returns></returns> 
    public List<TElement> ExecuteStoreQuery<TElement>(string commandText) 
    { 
     List<TElement> result = new List<TElement>(); 

     // Create a blocking collection to store the execution results from each task 
     // A blocking collection is a thread safe collection that can be updated by multiple tasks 
     BlockingCollection<ObjectResult<TElement>> bc = new BlockingCollection<ObjectResult<TElement>>(); 

     // Create a Task to run in paralled for each connection string 
     List<Task> tasks = new List<Task>(); 

     foreach (string connString in this.connectionStrings) 
     { 
      Task task = Task.Factory.StartNew(() => 
       { 
        // Create a new Connection 
        MyEntities entity = new MyEntities(connString); 
        this.contexts.Add(entity); 

        // Execute the query 
        var results = entity.ExecuteStoreQuery<TElement>(commandText); 

        // Add the results to the collection 
        if (results != null) 
        { 
         bc.Add(results); 
        } 


       }); 

      tasks.Add(task); 
     } 

     // Wait till all the tasks are done 
     try 
     { 
      Task.WaitAll(tasks.ToArray()); 
     } 
     catch (AggregateException ae) 
     { 
      ae.Handle((x) => 
       { 
        if (x is UnauthorizedAccessException) // This exception is known and we can handle it 
        { 
         return true; 
        } 
        else 
        { 
         return false; 
        } 
       }); 
     } 

     // Add each item in blocking list to our result set 
     foreach (var item in bc) 
     { 
      result.AddRange(item); 
     } 

     return result; 
    } 

でも、私は別の質問を持っています。 DBへの接続が失敗した場合でも、メソッドが結果を返すようにしたい。 5台のサーバのうち、少なくとも1台のサーバに接続できれば、結果を返すことになり、5台のサーバすべてに接続できなかった場合にのみ、失敗/例外をスローします。

どうすればよいですか?

答えて

2

BackgroundWorkerの代わりに、パラレルタスクライブラリまたは手動で作成されたスレッドを使用します。接続文字列をスレッド/タスクに渡してコンテキストを作成します(コンテキストはスレッドセーフではないため、スレッドで直接処理する必要があります)。問合せを実行し、結果を主リクエスト処理スレッドに戻します。ここで、結果セットを結合します。

+0

私はTPLを試しましたが、これは私が思いついたものです – user330612

関連する問題