Press "Enter" to skip to content

Copiare dati fra Database con ADO.Net

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.

sc_daquiali_solution01

clicchiamo su entrambi i Database e impostiamo nella finestra proprietà degli stessi le seguenti property:

  • Build Action = Content
  • Copy to Output directory = Copy Always

sc_daquiali_dbprop01

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:

sc_daquiali_form01

sc_daquiali_cartelle01

sc_daquiali_files01

 

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.

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.