А ADO.NET + массивные ВСТАВКИ + Excel + C # = "Плохое время"? - PullRequest
1 голос
/ 11 ноября 2008

В основном мне нужно вставить кучу данных в файл Excel. Создание соединения OleDB, кажется, самый быстрый способ, но я видел, что столкнулся с проблемами памяти. Память, используемая процессом, кажется, продолжает расти, когда я выполняю INSERT-запросы. Я сузил их, чтобы они происходили только при выводе в файл Excel (память остается неизменной без вывода в Excel). Я закрываю и снова открываю соединение между каждым рабочим листом, но это, похоже, не влияет на использование памяти (как и Dispose ()). Данные пишутся успешно, как я могу проверить с относительно небольшими наборами данных. Если у кого-то есть понимание, это будет оценено.

initializeADOConn () вызывается в конструкторе

initADOConnInsertComm () создает запрос вставки с параметризацией вставки

writeRecord () вызывается всякий раз, когда пишется новая запись. Новые рабочие листы создаются по мере необходимости.

public bool initializeADOConn()
        {
            /* Set up the connection string and connect.*/
            string connectionString = @"Provider=Microsoft.Jet.OLEDB.4.0;" +
                "Data Source=" + this.destination + ";Extended Properties=\"Excel 8.0;HDR=YES;\"";
            //DbProviderFactory factory =
                //DbProviderFactories.GetFactory("System.Data.OleDb");
            conn = new OleDbConnection(connectionString);
            conn.ConnectionString = connectionString;
            conn.Open();

            /* Intialize the insert command. */
            initADOConnInsertComm();
            return true;
        }
    public override bool writeRecord(FileListerFileInfo file)
            {
                /* If all available sheets are full, make a new one. */
                if (numWritten % EXCEL_MAX_ROWS == 0)
                {
                    conn.Close();
                    conn.Open();
                    createNextSheet();
                }
                /* Count this record as written. */
                numWritten++;
                /* Get all of the properties of the FileListerFileInfo record and add
                 * them to the parameters of the insert query. */
                PropertyInfo[] properties = typeof(FileListerFileInfo).GetProperties();
                for (int i = 0; i < insertComm.Parameters.Count; i++)
                    insertComm.Parameters[i].Value = properties[i].GetValue(file, null);
                /* Add the record. */
                insertComm.ExecuteNonQuery();

                return true;
            }

EDIT:

Нет, я вообще не пользуюсь Excel. Я намеренно избегаю Interop.Excel из-за его плохой работы (по крайней мере, из-за моих увлечений).

Ответы [ 3 ]

2 голосов
/ 11 ноября 2008

Ответ Да , формула, которую вы описываете , означает равное плохое время.

Если у вас есть удобная база данных (для этого подойдут SQL Server или Access), вы можете выполнить все вставки в таблицу базы данных, а затем сразу экспортировать таблицу в электронную таблицу Excel.

Вообще говоря, базы данных хороши в обработке большого количества вставок, а электронные таблицы - нет.

1 голос
/ 11 ноября 2008

Вот пара идей:

Открыта ли целевая рабочая книга? Существует ошибка ( Утечка памяти возникает при запросе открытого листа Excel с использованием объектов данных ActiveX ), который на самом деле IIRC находится в поставщике OLE DB для Jet (который вы используете), хотя это не подтверждается в вышеуказанной статье.

Несмотря на это, кажется, что массовая вставка - это то, что нужно.

Для этого вы можете использовать того же поставщика Jet OLE DB: все, что вам нужно - это таблица из одной строки. Вы могли бы даже изготовить один на лету. Чтобы создать новую книгу Excel, выполните CREATE TABLE DDL, используя несуществующий файл xls в строке подключения, и поставщик создаст для вас книгу с рабочим листом для представления таблицы. У вас есть подключение к вашей книге Excel, чтобы вы могли выполнить это:

CREATE TABLE [EXCEL 8.0;DATABASE=C:\MyFabricatedWorkbook;HDR=YES].OneRowTable 
(
   x FLOAT
);

(ИМО даже лучше было бы изготовить базу данных Jet, т.е. файл .mdb).

Используйте INSERT для создания фиктивной строки:

INSERT INTO [EXCEL 8.0;DATABASE=C:\MyFabricatedWorkbook;HDR=YES].OneRowTable (x) 
   VALUES (0);

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

INSERT INTO MyExcelTable (key_col, data_col)
SELECT DT1.key_col, DT1.data_col
FROM (
   SELECT 22 AS key_col, 'abc' AS data_col
   FROM [EXCEL 8.0;DATABASE=C:\MyFabricatedWorkbook;HDR=YES].OneRowTable
   UNION ALL
   SELECT 55 AS key_col, 'xyz' AS data_col
   FROM [EXCEL 8.0;DATABASE=C:\MyFabricatedWorkbook;HDR=YES].OneRowTable
   UNION ALL
   SELECT 99 AS key_col, 'efg' AS data_col
   FROM [EXCEL 8.0;DATABASE=C:\MyFabricatedWorkbook;HDR=YES].OneRowTable
) AS DT1;
0 голосов
/ 11 ноября 2008

Вместо того, чтобы писать по одной записи за раз, можете ли вы найти способ вставить в Bulk Bulk? Я стараюсь не использовать сумасшедшие вещи из DataSet, но разве нет способа сначала сделать все ваши вставки локальными, а затем заставить их работать одним махом? Это процессы открывает Excel в фоновом режиме? Умирают ли эти процессы впоследствии?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...