以下linq声明:
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();
如果我添加并行foreach并删除所有三个线程(backgroundworker,taskfactory和最里面的线程),那么系统会冻结,我不会在每次迭代时都进行更新。
答案 0 :(得分:1)
我认为你不能在单个ADO.NET连接上进行并行查询,至少不能与常见的提供者进行并行查询。即使使用Entity Framework(从版本6开始提供异步功能),您也需要创建多个上下文(每个都有自己的连接)来进行并行查询。
This link适用于Entity Framework,但我相信任何ADO.Net DataReader都是如此。引用:
但是...... EF不支持通过相同的DbContext对象处理多个请求。如果同一个DbContext实例上的第二个异步请求在第一个请求完成之前启动(并且这就是整个点),那么您将收到一条错误消息,指出您的请求正在处理打开的DataReader。
也就是说,如果查询不需要彼此的信息,那么没有什么可以阻止你打开不同的连接并且并行查询,而不是相同的。
考虑到在最常见的情况下,对于像这样的简单查询,大部分时间都用于实际传输结果数据(而不是查询本身),在这种情况下,我不会&#39 ;并认为并行处理会有所帮助(除非有某种网络限制限制每个客户端端口的数据传输速率,或类似的东西)
答案 1 :(得分: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),我可以用它来比较列类型