2012-04-15 2 views
2

Итак, я пытаюсь автоматизировать Microsoft Access с C#. Очевидно, что вы не можете выполнять код VBA асинхронно в VBA, но моя идея состояла в том, чтобы перевести это из C# с помощью делегатов.Будет ли этот код VBA выполняться асинхронно

У нас есть устаревшая система отчетности, которая запускает сотни запрограммированных запросов для получения информации, и эти запросы выполняются синхронно внутри макросов. Каждый запрос был спроектирован с использованием конструктора запросов MS Access и запрашивает базу данных MySql по ODBC. Они занимают 2-3 минуты для запуска, а макрос может содержать < = 20 запросов, то есть макрос займет большую часть часа для запуска. Если бы я запустил эти асинхронные операции, я мог бы запустить весь макрос через пару минут.

Мой полный C# код ниже:

using System; 
using Microsoft.Office.Interop.Access; 

namespace AsyncVBA 
{ 
    class Program 
    { 
     private static Application ap; 
     private delegate void ExportThread(string queryName, string exportLocation); 

     private static int count; 

     static void Main(string[] args) 
     { 
      var dbName = @"C:\Users\JMK\Desktop\MyDatabase.accdb"; 
      count = 0; 

      ExportThread queryThread = new ExportThread(ExportQuery); 

      ap = new Application(); 
      ap.OpenCurrentDatabase(dbName); 

      queryThread.BeginInvoke("qryOne", @"C:\Users\JMK\Desktop\x\one.xlsx", null, null); 
      queryThread.BeginInvoke("qryTwo", @"C:\Users\JMK\Desktop\x\two.xlsx", null, null); 
      queryThread.BeginInvoke("qryThree", @"C:\Users\JMK\Desktop\x\three.xlsx", null, null); 
      queryThread.BeginInvoke("qryFour", @"C:\Users\JMK\Desktop\x\four.xlsx", null, null); 
      queryThread.BeginInvoke("qryFive", @"C:\Users\JMK\Desktop\x\five.xlsx", null, null); 
      queryThread.BeginInvoke("qrySix", @"C:\Users\JMK\Desktop\x\six.xlsx", null, null); 
      queryThread.BeginInvoke("qrySeven", @"C:\Users\JMK\Desktop\x\seven.xlsx", null, null); 
      queryThread.BeginInvoke("qryEight", @"C:\Users\JMK\Desktop\x\eight.xlsx", null, null); 
      queryThread.BeginInvoke("qryNine", @"C:\Users\JMK\Desktop\x\nine.xlsx", null, null); 
      queryThread.BeginInvoke("qryTen", @"C:\Users\JMK\Desktop\x\ten.xlsx", null, null); 

      while (count < 10) 
      { 
       Console.ReadLine(); 
      } 

      ap.CloseCurrentDatabase(); 
     } 

     private static void ExportQuery(string queryName, string exportLocation) 
     { 
      ap.DoCmd.TransferSpreadsheet(AcDataTransferType.acExport, AcSpreadSheetType.acSpreadsheetTypeExcel9, queryName, exportLocation); 
      count++; 
     } 

    } 
} 

У меня возникли два вопроса, в настоящее время, во-первых, что мой код до сих пор, кажется, выполнение синхронно, это могло быть связано с ограничением в MS Access. Я предполагаю, что MS Access ставит в очередь запросы, получая их или что-то в этом роде. Вторая, менее важная проблема заключается в том, что мой счет, кажется, не увеличивается.

Куда я иду не так?

Благодаря

+0

Учитывается статическая переменная? – Paparazzi

+0

Да, это проблема? – JMK

+0

Нет, он должен запустить код VBA. Асинхронно используя C#, экспорт является всего лишь примером типа кода VBA, который я хочу запустить. – JMK

ответ

2

На самом деле, запуск слова, Excel, точки питания или любого офисного набора не будет работать асинхронно. Фактически, если вы создали экземпляр SQL-сервера, вы найдете то же самое. (большая разница между отправкой SQL-команды в процесс SQL SEPARATE в отличие от создания экземпляра in-process.

Я хотел бы записать эти данные в текстовый файл или даже в таблицу temp, а затем shell() out экземпляр приложения, находящегося при запуске, запускает серию запросов. Вы даже можете создать здесь сценарий Windows, который будет выполнять эти команды. Таким образом, вы получите отдельный экземпляр и поток, и поэтому ваше приложение не будет ждать.

1

Ничто в Microsoft Access был разработан, чтобы работать в то же время, как и все остальное. Я уверен, что когда вы успешно открываете базу данных Access, вы получаете эксклюзивную блокировку для всех системных таблиц. Я не вижу, как это может работать любым другим способом.

Гораздо лучший подход заключается в извлечении SQL из базы данных Access. Вы говорите, что каждый запрос был спроектирован с использованием конструктора запросов (я думаю, вы имеете в виду дизайн-представление), но у него все еще есть SQL, к которому вы можете обратиться. Просто переключитесь с дизайна на SQL-представление, и там у вас есть

+0

Хмм я пытался избежать этого. Проблема здесь в том, что SQL - это не MySQL, поэтому каждый запрос должен быть преобразован, тогда имена связанных таблиц все были изменены в Access, например, tblOne в MySql может быть изменен на tblAccessOne внутри Access, что означает что каждый экземпляр tblAccessOne внутри каждого запроса нужно изменить на tblOne для непосредственного запроса MySql-запроса. Это то, что я делал изначально, и очень быстро стало очень грязно! – JMK

+0

Вы можете создавать представления MySQL, чтобы имитировать запросы выбора доступа MS Access. SQL не будет таким разным. –

7

Просто имея большой опыт работы с Access как интерфейсом, лучше всего изменить все запросы на сквозные запросы и переписать их в синтаксисе mySQL.

причина, по которой текущий метод занимает много времени, вероятно, что набор данных, переданный по сети, намного больше, чем нужно. Доступ проходит через то, что может интерпретировать mySQL DB, а затем применяет остальную часть синтаксиса sql по прибытии. Это очень неэффективно для больших наборов данных.

+0

Я спросил об этом довольно давно, но, спасибо, что нашел время, чтобы ответить, с тех пор я понял это с самого начала, и действительно переписал много запросов в MySQL – JMK

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