Как выполнить SQL-запрос для нескольких баз данных параллельно и вернуть объединенные результаты с помощью ADO.NET Entity Framework - PullRequest
3 голосов
/ 21 декабря 2011

enter code here В моем веб-приложении у меня есть 5 экземпляров базы данных с одинаковыми схемами таблиц на разных серверах SQL.Я хочу выполнить SQL-запрос (или запросы) с помощью метода ExecuteStoreQuery (), доступного в Objectcontext, ко всем этим 5 базам данных / серверам параллельно и вернуть объединенные результаты.Меня не волнуют дубликаты, поэтому UNION всех результатов всех БД будет работать для меня.

Сначала я хотел сохранить строки подключения ко всем этим 5 БД в моем файле web.config и в моемкод, просмотрите каждую строку подключения и создайте экземпляр объекта Enitites со строкой подключения в качестве параметра, а затем используйте BackGroundWorker, чтобы выделить один поток на строку подключения и выполнить один и тот же запрос для всех БД параллельно, по одному выполнению в каждом потоке, а затем объединитьнаборы результатов из всех потоков в конце.

Это должно работать, но мне интересно, есть ли лучший способ решить эту проблему и есть ли в EF какие-либо встроенные методы, которые позволяют мне делать это без менявозиться с параллельным выполнением через потоки.

Есть идеи?

ОБНОВЛЕНИЕ

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

У меня есть еще один вопрос.Я хочу, чтобы мой метод возвращал результаты, даже если некоторые из соединений с БД перестали работать.Таким образом, из 5 серверов, если я могу подключиться по крайней мере к 1 серверу, то я хочу вернуть результаты и выдать ошибку / исключение, только если мне не удалось подключиться ко всем 5 серверам.

Какя делаю это?

1 Ответ

2 голосов
/ 21 декабря 2011

Вместо BackgroundWorker используйте либо параллельную библиотеку задач, либо созданные вручную потоки.Передайте строку подключения в поток / задачу и создайте там контекст (контекст не является потокобезопасным, поэтому он должен обрабатываться непосредственно в потоке).Выполните ваши запросы и верните результат в основной поток обработки запросов, где вы объединяете наборы результатов.

...