Sul forum nei giorni scorsi è stato chiesto come fare a copiare una tabella da un DB access ad un altro aggiungendovi una colonna, avendo già creato la tabella destinazione nel DB access di destinazione. Vediamo un metodo semplice per farlo usando ADO.NET. A seguito di una domanda su un forum, ho preparato un esempio per spiegare come copiare il contenuto di una tabella da un database Access ad un altro aggiungendo alla tabella di destinazione un dato in una colonna.
Per l’esempio ho creato 2 database access in formato 2000 che ho chiamato rispettivamente:
- daqui.mdb
- ali.mdb
Nel primo dei database ho generato 2 tabelle con la seguente struttura:
- daqui.tbdaqui
- ID = contatore intero automatico
- Targa = testo
- Marca = testo
- Motore = testo
- Cilindrata = intero
- Bollo = doppia precisione
- In questa tabella ho inserito una serie di record perché li copieremo nel db “Ali”
- daqui.tbali
- ID = Contatore intero automatico
- Nome = testo
- Cognome = testo
- Data = datetime
- Citta = testo
- CodiceFiscale = testo
- Addin = testo
- Questa tabella rimane vuota perché vi copieremo i dati che inseriremo nell’altro DB
Nel secondo dei database ho generato 2 tabelle con la seguente struttura:
- ali.tbdaqui
- ID = Contatore intero automatico
- Nome = testo
- Cognome = testo
- Data = datetime
- Citta = testo
- CodiceFiscale = testo
- In questa tabella ho inserito una serie di record perchè li copieremo nel db “daqui”
- ali.tbali
- ID = contatore intero automatico
- Targa = testo
- Marca = testo
- Motore = testo
- Cilindrata = intero
- Bollo = doppia precisione
- Addin = testo
- Questa tabella è vuota perché vi copieremo i dati inseriti nell’altro DB
Vi ho già confuso? Era voluto ovviamente ma visto che ho deciso di chiamare il progetto Da Qui A Lì e Da Lì a Qui ovviamente mi scuserete.
Il progetto
Per costruire il nostro trasferitore di tabelle apriamo Visual Studio 2008 e creiamo un nuovo progetto di tipo WinForms
lo chiameremo DnwDaQuiALi.
Rinominiamo la Form1 -> FrmDaQuiALi e andiamo ad aggiungervi i seguenti componenti:
- btnRigenera = button, Text = “Rigenera DB”.
- btnDaQuiALi = button, Text = “Copia Da Qui A Lì”.
- btnDaLiAQui = button, Text = “Copia Da Lì A Qui”.
- txtResult = textbox, Text = “”, Multiline = true, Scrollbars = vertical, Dock = bottom.
Nel nostro progetto generiamo una cartella che chiamiamo Dbase (Tasto destro, New Folder sul progetto nel solution explorer). Creiamo una sottocartella che chiamiamo Originali, tasto destro su questa cartella e usiamo Add >Existing Item per aggiungervi i nostri 2 database.
clicchiamo su entrambi i Database e impostiamo nella finestra proprietà degli stessi le seguenti property:
- Build Action = Content
- Copy to Output directory = Copy Always
In questo modo, quando compileremo il progetto, sulla cartella Bin\Debug verranno copiati anche i files mdb originali.
Il Codice
Per iniziare creiamo l’event handler del bottone Rigenera DB, questo bottone ha semplicemente il compito di copiare i 2 database dalla cartella Originali alla cartella Dbase. In modo che la nostra applicazione sia ripetibile.
Per fare la copia dei files ci servono i PATH sorgente e destinazione quindi nella nostra form creiamo il seguente codice:
private const string BasePath = "C:\\Dotnetwork\\DaQuiALi";
private const string PATHSourceDaqui = "DBase\\Originali\\daqui.mdb";
private const string PATHDestDaqui = "C:\\Dotnetwork\\DaQuiALi\\daqui.mdb";
private const string PATHSourceAli = "Dbase\\Originali\\Ali.mdb";
private const string PATHDestAli = "C:\\Dotnetwork\\DaQuiALi\\Ali.mdb";
Fatto questo, creiamo l’event handler:
private void btnRiGenera_Click(object sender, EventArgs e)
{
if (!Directory.Exists(BasePath))
{
Directory.CreateDirectory(BasePath);
}
File.Copy(PATHSourceDaqui, PATHDestDaqui, true);
File.Copy(PATHSourceAli, PATHDestAli, true);
FileInfo[] files = new DirectoryInfo(BasePath).GetFiles();
this.txtResult.Text = "Lista DB Copiati:" + Environment.NewLine;
for (int i = 0; i < files.Length; i++)
{
this.txtResult.Text += files[i].FullName + Environment.NewLine;
}
}
Utilizziamo la funzione Copy della classe File di System.IO per creare un metodo che fa una copia dei database originali sulla cartella Dbase, fatto questo, per mostrare che ha fatto qualcosa, visualizza i path dei files copiati sulla textbox txtResult.
Se lanciamo l’applicazione e premiamo il bottone evidenziato otteniamo il seguente risultato:
Se guardiamo la struttura di progetto con il File manager di windows, vediamo che sulla cartella Dbase abbiamo una copia dei files che sono sulla cartella Originali. Come avete potuto vedere, quando viene creata l’applicazione, il compilatore si occupa anche di rigenerare le 2 cartelle di contenuto come da noi richiesto.
Veniamo ora al primo bottone, Copia Da Qui a Lì, che si occupa di copiare la tabella Daqui.tbDaQui nella tabella Ali.tbAli, ovvero copia il contenuto della tabella che contiene i dati delle automobili dal Db DaQui.mdb, al Db Ali.mdb.
Prima di tutto creiamo il necessario a livello di classe per connetterci ai 2 database.
private const string CNStringDaQui = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Persist Security Info=True;";
private const string CNStringAli = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Persist Security Info=True;";
Le costanti contengono Il necessario per connettersi al database ed il necessario per generare la cartella ove copiare i files dal progetto per poterli rigenerare quando necessario.
Partiamo con il nostro Event handler creandone la struttura:
private void btnDaQuiAli_Click(object sender, EventArgs e)
{
try
{
...
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "ERRORE!",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
Creiamo una struttura Try Catch per controllare gli errori.
All’ interno del costrutto Try inseriremo il nostro codice per la copia dati. Ma prima, andiamo a definire due costanti con le stringhe SQL per leggere e scrivere i dati nei 2 database:
private const string SQL_SELECTDAQUI_TbDaqui = @"
SELECT TbDaqui.ID, TbDaqui.Targa, TbDaqui.Marca,
TbDaqui.Motore, TbDaqui.Cilindrata, TbDaqui.Bollo
FROM TbDaqui;";
private const string SQL_INSERTALI_TbAli = @"
INSERT INTO TbAli (Targa, Marca, Motore,
Cilindrata, Bollo, Addin )
VALUES (?,?,?,?,?,?);";
La prima stringa, legge tutti i campi della tabella TbDaQui del database DaQui.mdb.
La seconda effettua un inserimento dei dati nella tabella TbAli del database Ali.mdb
Andiamo a costruire ora il codice della Try del nostro event handler.
DataTable dtDaQui = null;
using (OleDbConnection mCnDaqui = new OleDbConnection(string.Format(CNStringDaQui, PATHDestDaqui)))
{
OleDbCommand cmdRead = new OleDbCommand();
cmdRead.Connection = mCnDaqui;
cmdRead.CommandText = SQL_SELECTDAQUI_TbDaqui;
cmdRead.CommandType = CommandType.Text;
mCnDaqui.Open();
OleDbDataReader dr = cmdRead.ExecuteReader();
dtDaQui = new DataTable();
if (dr.HasRows)
{
dtDaQui.Load(dr);
}
dr.Close();
mCnDaqui.Close();
}
In questa prima porzione di codice, creiamo un OleDbCommand per parlare al database DaQui.mdb usando la sua connessione ed il codice SQL per la select, Utilizziamo un DataReader per leggere il contenuto della tabella e carichiamo i dati trovati su una DataTable che costruiamo automaticamente dalla struttura del DataReader.
Riempita la Datatable, vediamo come procedere:
if (dtDaQui != null)
{
using (OleDbConnection mCnAli = new OleDbConnection(string.Format(CNStringAli,PATHDestAli)))
{
int conta = 0;
mCnAli.Open();
foreach (DataRow row in dtDaQui.Rows)
{
conta++;
OleDbCommand cmdWrite = new OleDbCommand();
cmdWrite.Connection = mCnAli;
cmdWrite.CommandText = SQL_INSERTALI_TbAli;
cmdWrite.CommandType = CommandType.Text;
for (int j = 1; j < row.Table.Columns.Count; j++)
{
cmdWrite.Parameters.Add(
new OleDbParameter(row.Table.Columns[j].ColumnName,
row[j]));
}
cmdWrite.Parameters.Add(
new OleDbParameter("Addin",
string.Format("Riga N. {0}", conta)));
this.txtResult.Text +=
string.Format("Riga N. {0} Targa {1}",
conta, row[1]) + Environment.NewLine;
cmdWrite.ExecuteNonQuery();
}
mCnAli.Close();
}
}
Per ognuna delle righe della datatable sorgente, creiamo un OleDbCommand contenente la stringa SQL di inserimento all’interno del database Ali.mdb, per fornire i dati da inserire, utilizziamo un ciclo for sui campi della DataRow a partire da quello con indice 1 per escludere il contatore automatico che non deve essere inserito.
Copiati tutti i campi della riga, aggiungiamo il campo Addin che non esiste nella tabella di origine e vi inseriamo all’interno una stringa che ci dice il numero di riga letta.
Aggiorniamo il nostro txtRexult.Text sulla form per mostrare cosa facciamo, chiamando il metodo Application.DoEvents per far aggiornare lo schermo. Infine, apriamo la connessione ed eseguiamo il command appena generato inserendo il dato nella tabella di destinazione.
Il bottone contrario
Sull’event handler del bottone “Copia Da Li A Qui” eseguiamo l’operazione rovescia, copiando dalla tabella Ali.TbDaQui alla tabella DaQui.TbAli.
private const string SQL_SELECTALI_TbDaQui = @"
SELECT TbDaQUi.ID, TbDaQUi.Nome, TbDaQUi.Cognome,
TbDaQUi.Data, TbDaQUi.Citta, TbDaQUi.CodiceFiscale
FROM TbDaQUi;";
private const string SQL_INSERTDAQUI_TbAli = @"
INSERT INTO TbAli (Nome, Cognome, Data,
Citta, CodiceFiscale, Addin )
VALUES (?,?,?,?,?,?);";
Le costanti per la selezione dei dati nella tabella sorgente e l’inserimento nella tabella destinazione.
private void btnDaLiAQui_Click(object sender, EventArgs e)
{
try
{
DataTable dtDaQui = null;
using (OleDbConnection mCnAli = new OleDbConnection(string.Format(CNStringAli,PATHDestAli)))
{
OleDbCommand cmdRead = new OleDbCommand();
cmdRead.Connection = mCnAli;
cmdRead.CommandText = SQL_SELECTALI_TbDaQui;
cmdRead.CommandType = CommandType.Text;
mCnAli.Open();
OleDbDataReader dr = cmdRead.ExecuteReader();
dtDaQui = new DataTable();
if (dr.HasRows)
{
dtDaQui.Load(dr);
}
dr.Close();
mCnAli.Close();
}
if (dtDaQui != null)
{
using (OleDbConnection mCnDaqui = new OleDbConnection(string.Format(CNStringDaQui, PATHDestDaqui)))
{
mCnDaqui.Open();
int conta = 0;
foreach (DataRow row in dtDaQui.Rows)
{
conta++;
OleDbCommand cmdWrite = new OleDbCommand();
cmdWrite.Connection = mCnDaqui;
cmdWrite.CommandText = SQL_INSERTDAQUI_TbAli;
cmdWrite.CommandType = CommandType.Text;
for (int j = 1; j < row.Table.Columns.Count; j++)
{
cmdWrite.Parameters.Add(
new OleDbParameter(row.Table.Columns[j].ColumnName,
row[j]));
}
cmdWrite.Parameters.Add(
new OleDbParameter("Addin",
string.Format("Riga N. {0}", conta)));
this.txtResult.Text +=
string.Format("Riga N. {0} Nome {1} Cognome {2}",
conta, row[1], row[2]) + Environment.NewLine;
cmdWrite.ExecuteNonQuery();
}
mCnDaqui.Close();
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "ERRORE!",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
Stesso procedimento rovesciando i Database.
Per rigenerare i database e ripetere la copia, abbiamo creato un tasto che copia i 2 database allegati al progetto in una cartella sul disco C:.
Conclusioni
Ovviamente non si tratta dell’unico modo per copiare dati fra due database, si poteva semplificare ulteriormente la funzionalità non usando la datatable ma leggendo direttamente il DataReader. Oppure si poteva fare una applicazione più strutturata creando due DataAdapter e due Dataset, ma se l’operazione da farsi è una cosa Brutale e semplice come questa, credo che il metodo sia buono. Ovviamente, i dati Sorgente, potrebbero anche essere una query da più tabelle, potrebbero contenere dei filtri (WHERE) per selezionare una porzione di dati in base alle esigenze. L’applicazione ovviamente sta a chi legge l’articolo.
Potete fare commenti, domande, chiedere approfondimenti o indicare se trovate errori usando il modulo di contatto che trovate a inizio pagina, e potete scaricare il codice dell’esempio dal link qui sotto.
Companion code, Copiare dati fra database con ADO.Net
Nota: Abbiamo convertito il progetto al framework 4.5.2 nel 2017 e questa è la versione aggiornata, inoltre abbiamo modificato il progetto per fare in modo sia compilato a 32 bit, perché compilandolo a 64bit il driver di OleDb non viene trovato (perché è a 32 bit) quindi viene sollevata un eccezione che indica che il driver non è installato.