czwartek, 6 marca 2008

Kopia bazy ODBC do pliku mdb

Ostatnio miałem potrzebę zrobienia kopii bazy systemu, nad którym aktualnie pracuję. Docelowo chciałbym do wszystkich tabel dodać logowanie zmian, ale do tego czasu chciałem mieć czytelne migawki danych. Z tej racji, że baza źródłowa jest na razie dość mała, oraz ze względu na powszechność jako format docelowy wybrałem mdb, czyli bazę accessową.

Archiwizacja danych odbywa się w dwóch fazach:

  1. pobranie listy tabel przy użyciu metody GetSchema i ODBC,
  2. utworzenie w pętli tabel wynikowych za pomocą accessowej składni Select * Into TabelaWynikowa From TabelaZrodlowa IN '' [ODBC;CiagPolaczenia];

Kod nieco uproszczonej wersji:

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Odbc;
using System.Data.OleDb;

namespace GdnKonsulting.BackupToMdbLogic
{
public class TransferData
{
private readonly string connectionString;
private readonly string schemaName;
private readonly string tmpFile;
private readonly string outputFileName;

public TransferData(string connectionString, string schemaName,
string outputFileName)
{
this.connectionString = connectionString;
this.schemaName = schemaName;
this.outputFileName = outputFileName;
this.tmpFile = System.IO.Path.GetTempFileName();
}

public void CreateDbAndTransferAllTables()
{
AdoxWorker.CreateDatabase(this.tmpFile);
List<string> tablesList = ReadTablesList();
ImportDataToDb(this.tmpFile, tablesList);
}

private List<string> ReadTablesList()
{
using (OdbcConnection connection = new OdbcConnection(connectionString))
{
                connection.Open();
DataTable tables = connection.GetSchema("TABLES",
new string[] { null, schemaName });
                List<string> result = new List<string>();
foreach (DataRow row in tables.Rows)
{
result.Add(tableName);
}
return result;
}
}

private void ImportDataToDb(string outputFileName, List<string> tablesList)
{
string connectionString = String.Format("Provider=Microsoft.Jet.OLEDB.4.0;" +
"Data Source={0}", outputFileName);

using (OleDbConnection connection = new OleDbConnection(connectionString))
{
OleDbCommand command = connection.CreateCommand();

connection.Open();
foreach (string tableName in tablesList)
{
string commandText = String.Format(
"Select * Into {0} From {1} IN '' [ODBC;{2}];",
tableName, tableName, this.connectionString);

command.CommandText = commandText;
command.ExecuteNonQuery();
}
}
}
}
}

I przykładowe wywołanie:

string connectionString = "Driver={Microsoft ODBC for Oracle};" +
"Server=ORCL;Uid=userName;Pwd=hasło;";

TransferData transfer = new TransferData(
connectionString, "userName", "C:\Backup.mdb");

W wersji produkcyjnej mam kilka ulepszeń:



  1. kompresję pliku accessowego.
  2. dodanie zdarzenia wywoływanego po udanym zapisie tabeli do pliku wyjściowego, by niezwłocznie informować o tym użytkownika,
  3. filtrowanie tabel (np. z oraclowych tabel znajdujących się w koszu, czyli o nazwach zaczynających się od "BIN$"),
  4. dodawanie do nazw tabel wynikowych nazwy schematu - na przewidywaną ewentualność importu danych z kilku schematów.

Aha, dodam jeszcze kod tworzący nowy plik mdb:

    public static class AdoxWorker
{
public static void CreateDatabase(string fileName)
{
ADOX.CatalogClass cat = new ADOX.CatalogClass();

cat.Create("Provider=Microsoft.Jet.OLEDB.4.0;" +
"Data Source=" + fileName + ";" +
"Jet OLEDB:Engine Type=5");
}
}

Jak widać jest to wersja wymagająca wcześniejszego podłączenia bibliotek ADOX


To byłoby na tyle :).

0 komentarze: