2015-01-21 2 views
0

ниже LINQ заявление:Ошибка с Linq команды -Есть уже открытое DataReader, связанные с этой командой, которая должна быть закрыта первая

List<Column> columns = table.Columns.Cast<Column>().SelectMany(t => table.Columns.Cast<Column>().Where(col => col.DataType.Equals(DataType.NVarChar(4000))).Select(col => col)).ToList(); 

занимает около 5 секунд, чтобы выполнить, и для 500+ таблиц, это очень долгое время. Я решил пойти на параллельный цикл. Итак, этот процесс не дожидался завершения строения и обработки следующей итерации. Но получаю ошибку - Существует уже открытая DataReader, связанные с этой командой, которая должна быть закрыта первая

Ниже мой код -

BackgroundWorker worker = new BackgroundWorker(); 
         worker.WorkerReportsProgress = true; 
         worker.WorkerSupportsCancellation = true; 
         worker.DoWork += (_, args) => 
          { 
           int count = 1; 
           foreach (Table table in DestinationTables) 
           { 
            Task.Factory.StartNew(() => 
             { 
              Thread thread = new Thread(new ThreadStart(() => 
               { 
                List<Column> columns = table.Columns.Cast<Column>().SelectMany(t => table.Columns.Cast<Column>().Where(col => col.DataType.Equals(DataType.NVarChar(4000))).Select(col => col)).ToList(); 
                if (columns.Count > 0) 
                 encryptedcolumns.Add(table.ToString(), columns); 
                Application.Current.Dispatcher.InvokeAsync(() => 
                 { 
                  worker.ReportProgress(count++); 
                 }); 


               })); 
              thread.Start(); 
             }).Wait(); 

           } 

          }; 
         worker.ProgressChanged += (_, args) => 
          { 
           ProgressBarCurrentValue = args.ProgressPercentage; 
           NotificationText[1] = "Configuration In Progress. " + Math.Round(Convert.ToDouble(progressBarCurrentValue * 100/progressBarMaximumValue) , 2) + "% Completed"; 
          }; 
         worker.RunWorkerCompleted += (_, args) => 
          { 
           NotificationText[1] = "Execution Started. Please wait"; 
           NotifyPropertyChanged("NotificationText"); 
           ExecuteWorker.RunWorkerAsync(); 
           NotifyPropertyChanged("ExecuteWorker"); 
          }; 
         worker.RunWorkerAsync(); 

Если добавить параллельный Еогеасп и удалить все три потоки (фоновая работа, taskfactory и innewost Thread), затем система зависает, и я не получаю обновления на каждой итерации.

+0

Если ответ, который я дал, решил проблему, пожалуйста, отметьте это как ответ. Спасибо ... –

ответ

1

Я не думаю, что вы можете выполнять параллельные запросы на одном подключении ADO.NET, а не на общих провайдерах. Даже с Entity Framework (который предоставляет функции async начиная с версии 6) вам нужно создать несколько контекстов (каждый со своим подключением) для параллельного запроса.

This link относится к платформе Entity Framework, но я считаю, что это то же самое для любого ADO.Net DataReader. Цитата:

Но ... EF не поддерживает обработку нескольких запросов через один и тот же объект DbContext. Если ваш второй асинхронный запрос в том же экземпляре DbContext запускается до завершения первого запроса (и это целая точка), вы получите сообщение об ошибке, которое ваш запрос обрабатывает с открытым DataReader.

При этом, если запросы не нуждаются в информации друг от друга, ничто не мешает вам открывать другое соединение и запрашивать параллельно, просто не с тем же.

Примите во внимание, что в наиболее распространенных случаях для простых запросов, подобных этому, большая часть времени тратится на фактическую передачу данных результата (а не самого запроса), и в этом случае я не знаю, t думаю, что параллельная обработка помогла бы (если не существует какой-либо сетевой кепки, которая ограничивает скорость передачи данных на клиентский порт или что-то в этом роде)

+0

Благодарим вас за подробное описание. Не могли бы вы сообщить мне, есть ли альтернативный способ выполнить данную операцию linq в течение короткого промежутка времени, так как я не уверен, почему для сравнения типа данных каждого столбца таблицы требуется время, поскольку соединение уже выполнено и данные таблицы уже выведены в список. –

+0

С данными, и не видя вашу базу данных, я понятия не имею. Я предполагаю (по вашим именам объектов), что вы используете Linq-To-DataSet, и я не знаю, как это работает. Если возможно, вы можете проверить полученный SQL и профиль ... Я знаю, что это возможно с Linq-To-Entities, проверяя возвращаемый 'IQueryable', но я никогда не использовал Linq-To-DataSet, поэтому я не знать. – Jcl

0

Спасибо за ваш ответ. В моем случае это работает -

string sqlcommand = "SELECT s.name + '.' + ts.name AS TableName, 
c.name AS column_name, 
t.name + '(' + Convert(varchar ,c.max_length/2) + ')' AS Datatypename,  
c.PRECISION, c.scale FROM sys.columns AS c 
INNER JOIN sys.types AS t ON c.user_type_id=t.user_type_id 
INNER JOIN sys.tables ts ON ts.OBJECT_ID = c.OBJECT_ID 
INNER JOIN sys.schemas s ON s.schema_id = ts.schema_id 
ORDER BY s.name + '.' + ts.name, c.column_id"; 

DataSet dtset = DestinationDB.ExecuteWithResults(sqlcommand); 

Здесь я могу получить типы столбцов для всех таблицы в наборе данных в секунде (по сравнению с часами: D), который я могу использовать для сравнения типов столбцов

+0

Это нормально, чтобы отвечать на ваши вопросы в Stack Overflow, однако в текущем состоянии это вообще не дает ответа на вопрос (поскольку вопрос касается точного исключения, которое возникает при выполнении параллельных операций над DataReader). Вы должны либо изменить свой вопрос, чтобы указать, что вам не нужен ответ (возможно, этот пост), либо задать реальный вопрос о проблеме с производительностью. Я рад, что вы нашли решение :-) – Jcl

Смежные вопросы

 Смежные вопросы