2009-02-05 12 views
5

Il mio progetto a cui sto lavorando è quasi finito. Sto caricando un file .MDB, visualizzando i contenuti su un DataGrid e tentando di ottenere quelle modifiche su DataGrid e salvarle nuovamente nel file .MDB. Creerò anche una funzione che mi consente di prendere le tabelle da un file .MDB e salvarlo in un altro file .MDB. Naturalmente, non posso fare nulla se non riesco a capire come salvare le modifiche nel file .MDB.C# Problema: qual è il modo più semplice per caricare un file .MDB, apportare modifiche e salvare le modifiche sul file originale?

Ho effettuato ricerche approfondite su Google e non ci sono risposte alla mia domanda. Mi considero un principiante su questo argomento specifico quindi per favore non rendere le risposte troppo complicate - Ho bisogno del modo più semplice per modificare un file .MDB! Si prega di fornire esempi di programmazione.

  1. Si supponga che ho già fatto una connessione a un DataGrid. Come posso ottenere le modifiche apportate da Datagrid? Sono sicuro che questo è abbastanza semplice da rispondere.
  2. Ho quindi bisogno di sapere come prendere questo Datatable, inserirlo nel Dataset da cui proviene, quindi prendere quel Dataset e riscrivere il file .MDB. (Se c'è un modo di inserire solo i tavoli che sono stati modificati preferirei quello.)

Grazie in anticipo, fammi sapere se hai bisogno di ulteriori informazioni. Questa è l'ultima cosa che probabilmente dovrò chiedere su questo argomento ... grazie a dio.

EDIT:

Il .mdb sto lavorando con un database di di Microsoft Access. (Non sapevo nemmeno che ci fossero più file .mdb)

So che non riesco a scrivere direttamente nel file .MDB tramite uno streamwriter o altro, ma c'è un modo per poter generare un file .MDB con le informazioni del DataSet già in esso? O c'è solo un modo per aggiungere tabelle a un file .MDB che ho già caricato in DataGrid. Ci deve essere un modo!

Anche in questo caso, ho bisogno di un modo per fare questo di programmazione in C#.

EDIT:

Va bene, il mio progetto è abbastanza grande, ma io uso un file di classe separato per gestire tutte le connessioni di database. So che il mio design e la mia fonte sono davvero sciatti, ma il lavoro è fatto. Sono solo buono come gli esempi che trovo su internet.

Ricorda, mi sto semplicemente connettendo a un DataGrid in un altro formato. Fammi sapere se vuoi il mio codice dal modulo Datagrid (non so perché ne avresti bisogno comunque). DatabaseHandling.cs gestisce 2 file .MDB. Quindi vedrai due dataset lì dentro. Lo userò per prendere le tabelle da un set di dati e metterle in un altro dataset. Ho solo bisogno di capire come salvare questi valori INDIETRO in un file .MDB.

Esiste comunque? Ci deve essere un modo ...

EDIT:

da quello che ho studiato e letto ... Penso che la risposta è proprio sotto il mio naso. Utilizzando il comando "Aggiorna()".Ora, mentre questo è rassicurante che c'è un modo semplice per farlo, mi rimane il problema che non ho idea di come usare questo comando di aggiornamento.

Forse posso configurarlo in questo modo:

Oledb.OledbConnection cn = new Oledb.OledbConnection(); 
cn.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\Staff.mdb"; 
Oledb.OledbCommand cmd = new Oledb.OledbCommand(cn); 
cmd.CommandText = "INSERT INTO Customers (FirstName, LastName) VALUES (@FirstName, @LastName)"; 

penso che possa farlo, ma non voglio inserire manualmente qualsiasi cosa. Voglio fare entrambe queste invece:

  • Prendete le informazioni che è cambiato sul DataGrid e aggiornare il file di database Access (.mdb) che ho preso da
  • creare una funzione che mi permette di prendere le tabelle da un altro file di database di Access (.mdb) e sostituirli in un file di database di Access secondario (.mdb). Entrambi i file utilizzeranno la stessa identica struttura ma avranno in essi informazioni diverse.

Spero che qualcuno abbia una risposta per questo ... il mio progetto è fatto, tutto ciò che attende è una semplice risposta.

Grazie ancora in anticipo.

EDIT:

Va bene ... una buona notizia. Ho capito come interrogare il file .mdb stesso (credo). Ecco il codice, che non funziona perché ottengo un errore di runtime a causa del comando sql che sto tentando di utilizzare. Quale mi porterà alla mia prossima domanda.

Nuovo codice funzione aggiunto DatabaseHandling.cs:

static public void performSynchronization(string table, string tableTwoLocation) 
{ 
    OleDbCommand cmdCopyTables = new OleDbCommand("INSERT INTO" + table + "SELECT * FROM [MS Access;" + tableTwoLocation + ";].[" + table + "]"); // This query generates runtime error 
    cmdCopyTables.Connection = dataconnectionA; 
    dataconnectionA.Open(); 
    cmdCopyTables.ExecuteNonQuery(); 
    dataconnectionA.Close(); 
} 

Come si può vedere, in realtà ho riuscito a eseguire una query sulla connessione in sé, che ritengo essere l'accesso vero e proprio. File MDB. Come ho già detto, la query SQL che ho eseguito sul file non funziona e ha generato un errore di run-time quando utilizzato.

Il comando che sto tentando di eseguire dovrebbe prendere una tabella da un file .MDB e sovrascrivere una tabella dello stesso tipo di un file .MDB differente. Il comando SQL che ho tentato in precedenza ha cercato di prendere direttamente una tabella da un file .mdb, e inserirla direttamente in un'altra - questo non è quello che voglio fare. Voglio prendere tutte le informazioni dal file .MDB - inserire le tabelle in un Datatable e quindi aggiungere tutti i Datatables a un set di dati (cosa che ho fatto.) Voglio farlo per due file .MDB. Una volta che ho due set di dati che vogliono prendere tabelle specifiche di ciascun set di dati e aggiungerli a ciascun file in questo modo:

  • DataSetA >>>> ----- [aggiungere tabelle (sovrascriverli)] - ---- >>>> DataSetB
  • DataSetB >>>> ----- [aggiungere tabelle (sovrascriverli)] ----- >>>> DataSetA

voglio prendi tutti quei Dataset e poi inseriscili in ciascun file .MDB di Access da cui provengono. Essenzialmente mantenendo entrambi i database sincronizzati.

Così le mie domande, rivisto, è:

  1. Come si crea una query SQL che aggiungerà una tabella per il file mdb sovrascrivendo quello esistente con lo stesso nome.La query dovrebbe essere in grado di essere creata dinamicamente durante il runtime con una matrice che sostituisce una variabile con il nome della tabella che voglio aggiungere.
  2. Come posso ottenere le modifiche apportate da Datagrid al DataTable e reinserirle in un DataTable (o DataSet) in modo da poterle inviare al file .MDB?

Ho cercato di elaborare il più possibile ... perché credo di non spiegare molto bene il mio problema. Ora questa domanda è diventata troppo lunga. Spero solo di poterlo spiegare meglio. : [

EDIT:

Grazie ad un utente sotto Credo di aver quasi trovato una soluzione - la parola chiave quasi. Ecco il seguente codice DatabaseHandling.cs aggiornato di seguito. Ottengo un errore di runtime "Datatype Mismatch". Non so come ciò potrebbe essere possibile considerando che sto cercando di copiare queste tabelle in un altro database con la stessa identica configurazione.

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Data.OleDb; 
using System.Data; 
using System.IO; 

    namespace LCR_ShepherdStaffupdater_1._0 
    { 
     public class DatabaseHandling 
     { 
      static DataTable datatableB = new DataTable(); 
      static DataTable datatableA = new DataTable(); 
      public static DataSet datasetA = new DataSet(); 
      public static DataSet datasetB = new DataSet(); 
      static OleDbDataAdapter adapterA = new OleDbDataAdapter(); 
      static OleDbDataAdapter adapterB = new OleDbDataAdapter(); 
      static string connectionstringA = "Provider=Microsoft.Jet.OLEDB.4.0;" + "Data Source=" + Settings.getfilelocationA(); 
      static string connectionstringB = "Provider=Microsoft.Jet.OLEDB.4.0;" + "Data Source=" + Settings.getfilelocationB(); 
      static OleDbConnection dataconnectionB = new OleDbConnection(connectionstringB); 
      static OleDbConnection dataconnectionA = new OleDbConnection(connectionstringA); 
      static DataTable tableListA; 
      static DataTable tableListB; 

      static public void addTableA(string table, bool addtoDataSet) 
      { 
       dataconnectionA.Open(); 
       datatableA = new DataTable(table); 
       try 
       { 
        OleDbCommand commandselectA = new OleDbCommand("SELECT * FROM [" + table + "]", dataconnectionA); 
        adapterA.SelectCommand = commandselectA; 
        adapterA.Fill(datatableA); 
       } 
       catch 
       { 
        Logging.updateLog("Error: Tried to get " + table + " from DataSetA. Table doesn't exist!"); 
       } 

       if (addtoDataSet == true) 
       { 
        datasetA.Tables.Add(datatableA); 
        Logging.updateLog("Added DataTableA: " + datatableA.TableName.ToString() + " Successfully!"); 
       } 

       dataconnectionA.Close(); 
      } 

      static public void addTableB(string table, bool addtoDataSet) 
      { 
       dataconnectionB.Open(); 
       datatableB = new DataTable(table); 

       try 
       { 
        OleDbCommand commandselectB = new OleDbCommand("SELECT * FROM [" + table + "]", dataconnectionB); 
        adapterB.SelectCommand = commandselectB; 
        adapterB.Fill(datatableB); 
       } 
       catch 
       { 
        Logging.updateLog("Error: Tried to get " + table + " from DataSetB. Table doesn't exist!"); 
       } 



       if (addtoDataSet == true) 
       { 
        datasetB.Tables.Add(datatableB); 
        Logging.updateLog("Added DataTableB: " + datatableB.TableName.ToString() + " Successfully!"); 
       } 

       dataconnectionB.Close(); 
      } 

      static public string[] getTablesA(string connectionString) 
      { 
       dataconnectionA.Open(); 
       tableListA = dataconnectionA.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, new Object[] { null, null, null, "TABLE" }); 
       string[] stringTableListA = new string[tableListA.Rows.Count]; 

       for (int i = 0; i < tableListA.Rows.Count; i++) 
       { 
        stringTableListA[i] = tableListA.Rows[i].ItemArray[2].ToString(); 
       } 
       dataconnectionA.Close(); 
       return stringTableListA; 
      } 

      static public string[] getTablesB(string connectionString) 
      { 
       dataconnectionB.Open(); 
       tableListB = dataconnectionB.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, new Object[] { null, null, null, "TABLE" }); 
       string[] stringTableListB = new string[tableListB.Rows.Count]; 

       for (int i = 0; i < tableListB.Rows.Count; i++) 
       { 
        stringTableListB[i] = tableListB.Rows[i].ItemArray[2].ToString(); 
       } 
       dataconnectionB.Close(); 
       return stringTableListB; 
      } 

      static public void createDataSet() 
      { 

       string[] tempA = getTablesA(connectionstringA); 
       string[] tempB = getTablesB(connectionstringB); 
       int percentage = 0; 
       int maximum = (tempA.Length + tempB.Length); 

       Logging.updateNotice("Loading Tables..."); 
       for (int i = 0; i < tempA.Length ; i++) 
       { 
        if (!datasetA.Tables.Contains(tempA[i])) 
        { 
         addTableA(tempA[i], true); 
         percentage++; 
         Logging.loadStatus(percentage, maximum); 
        } 
        else 
        { 
         datasetA.Tables.Remove(tempA[i]); 
         addTableA(tempA[i], true); 
         percentage++; 
         Logging.loadStatus(percentage, maximum); 
        } 
       } 

       for (int i = 0; i < tempB.Length ; i++) 
       { 
        if (!datasetB.Tables.Contains(tempB[i])) 
        { 
         addTableB(tempB[i], true); 
         percentage++; 
         Logging.loadStatus(percentage, maximum); 
        } 
        else 
        { 
         datasetB.Tables.Remove(tempB[i]); 
         addTableB(tempB[i], true); 
         percentage++; 
         Logging.loadStatus(percentage, maximum); 
        } 
       } 


      } 

      static public DataTable getDataTableA() 
      { 
       datatableA = datasetA.Tables[Settings.textA]; 

       return datatableA; 
      } 
      static public DataTable getDataTableB() 
      { 
       datatableB = datasetB.Tables[Settings.textB]; 
       return datatableB; 
      } 

      static public DataSet getDataSetA() 
      { 
       return datasetA; 
      } 

      static public DataSet getDataSetB() 
      { 
       return datasetB; 
      } 

      static public void InitiateCopyProcessA() 
      { 
       DataSet tablesA; 
       tablesA = DatabaseHandling.getDataSetA(); 

       foreach (DataTable table in tablesA.Tables) 
       { 
        CopyTable(table, connectionstringB); 
       } 
      } 

      public static void CopyTable(DataTable table, string connectionStringB) 
      { 
       var connectionB = new OleDbConnection(connectionStringB); 
       foreach (DataRow row in table.Rows) 
       { 
        InsertRow(row, table.Columns, table.TableName, connectionB); 
       } 
      } 

      public static void InsertRow(DataRow row, DataColumnCollection columns, string table, OleDbConnection connection) 
      { 
       var columnNames = new List<string>(); 
       var values = new List<string>(); 

       for (int i = 0; i < columns.Count; i++) 
       { 
        columnNames.Add("[" + columns[i].ColumnName + "]"); 
        values.Add("'" + row[i].ToString().Replace("'", "''") + "'"); 
       } 

       string sql = string.Format("INSERT INTO {0} ({1}) VALUES ({2})", 
         table, 
         string.Join(", ", columnNames.ToArray()), 
         string.Join(", ", values.ToArray()) 
        ); 

       ExecuteNonQuery(sql, connection); 
      } 

      public static void ExecuteNonQuery(string sql, OleDbConnection conn) 
      { 
       if (conn == null) 
        throw new ArgumentNullException("conn"); 

       ConnectionState prevState = ConnectionState.Closed; 
       var command = new OleDbCommand(sql, conn); 
       try 
       { 
        prevState = conn.State; 
        if (prevState != ConnectionState.Open) 
         conn.Open(); 

        command.ExecuteNonQuery(); // !!! Runtime-Error: Data type mismatch in criteria expression. !!! 
       } 
       finally 
       { 
        if (conn.State != ConnectionState.Closed 
         && prevState != ConnectionState.Open) 
         conn.Close(); 
       } 
      } 

      }   
     } 

Perché viene visualizzato questo errore? Entrambe le tabelle sono esattamente le stesse. Che cosa sto facendo di sbagliato? Nel peggiore dei casi, come faccio a eliminare la tabella nell'altro file Access .MDB prima di inserire la stessa tabella di struttura con valori diversi all'interno?

Uomo Vorrei poter solo questo numero ...

EDIT:

Va bene, sono venuto una certa distanza. La mia domanda si è trasformata in una nuova, e quindi merita di essere chiesta separatamente. Ho avuto risposta alla mia domanda poiché ora so come eseguire query direttamente sulla connessione che ho aperto. Grazie a tutti!

+0

@Remou: cercando di ottenere la vostra attenzione qui - si stanno facendo peggiorare la situazione. L'accesso! = MDB. Tutte queste domande che stai taggando da MDB a MS-ACCESS non comportano affatto l'accesso, ma solo il motore di database Jet/ACE. Sto taggando di conseguenza. –

+0

@Remou @David W. Fenton: ho sollevato questo problema su meta: http://meta.stackoverflow.com/questions/33216/ms-access-or-mdb-or-access-database-engine-or- ms-jet-ase – onedaywhen

+0

Ho già pubblicato su Meta. MDB eguaglia anche i bean basati sui messaggi, quindi è un tag ambiguo e, come Access, che è etichettato come ms-access a causa di ambiguità, deve essere modificato. – Fionnuala

risposta

3

Non sono sicuro di quanto si sia arrivati ​​lontano, ma se si sta cercando un'operazione di trascinamento veloce, si potrebbe voler creare un set di dati fortemente tipizzato che si connette e utilizzare le funzionalità di trascinamento di la finestra degli strumenti DataSource in Visual Studio.

Ci sono sicuramente dei campioni, ma lo vorrai.

  1. Creare un nuovo DataSet
  2. drag-n-drop dal tuo DataConnection Albero in Esplora server
  3. Crea una nuova forma
  4. Trascinare la tabella dalla Strumento DataSources
  5. Finestra al modulo .
  6. voilà

Aggiornamento:

Prima di tutto, io non sono al 100% che ho capito il problema. Se è possibile creare alcuni LinkTables tra i file di accesso che sarebbero i migliori, è possibile copiare i dati tra i file utilizzando un'istruzione sql come "INSERT INTO Customers SELECT FirstName, LastName FROM File2.Customers". Se non è così e l'opzione penso che dovrai eseguire il loop dei DataTable e inserire i record manualmente usando istruzioni INSERT simili alla tua ultima modifica. Per quanto riguarda il datagrid, probabilmente dovrai tenere traccia di ciò che è stato cambiato monitorando l'evento RowChanged (non sono sicuro se questo è l'evento esatto) anche di fare le istruzioni di inserimento/aggiornamento quando la riga cambia.

Aggiornamento:

al ciclo DataTable si dovrebbe fare qualcosa di simile. non testato. Ho appena aggiornato di nuovo per includere la funzione MakeValueDbReady. Anche questo non è stato testato e non sono sicuro di aver gestito correttamente tutti i casi o anche tutti i casi. Dovrai davvero eseguire il debug dell'istruzione sql e assicurarti che ne generi il giusto valore. Ogni database gestisce i valori in modo diverso. In questo modo l'analisi del valore viene estratta. Ho anche capito che invece di difficile codificare il TableName si dovrebbe essere in grado di ottenere da una proprietà sulla DataTable

void CopyTable(DataTable table, string connectionStringB) 
{ 
    var connectionB = new OleDbConnection(connectionStringB); 
    foreach(DataRow row in table.Rows) 
    { 
     InsertRow(row, table.Columns, table.TableName, connectionB); 
    } 
} 

public static void InsertRow(DataRow row, DataColumnCollection columns, string table, OleDbConnection connection) 
{ 
    var columnNames = new List<string>(); 
    var values = new List<string>(); 

    // generate the column and value names from the datacolumns  
    for(int i =0;i<columns.Count; i++) 
    { 
     columnNames.Add("[" + columns[i].ColumnName + "]"); 
     // datatype mismatch should be fixed by this function 
     values.Add(MakeValueDbReady(row[i], columns[i].DataType)); 
    } 

    // create the sql 
    string sql = string.Format("INSERT INTO {0} ({1}) VALUES ({2})", 
      table, 
      string.Join(", ", columnNames.ToArray()), 
      string.Join(", ", values.ToArray()) 
     ); 

    // debug the accuracy of the sql here and even copy into 
    // a new Query in Access to test 
    ExecuteNonQuery(sql, connection); 
} 

// as the name says we are going to check the datatype and format the value 
// in the sql string based on the type that the database is expecting 
public string MakeValueDbReady(object value, Type dataType) 
{ 
    if (value == null) 
     return null; 

    if (dataType == typeof(string)) 
    { 
     return "'" + value.ToString().Replace("'", "''") + "'" 
    } 
    else if (dataType == typeof(DateTime)) 
    { 
     return "#" + ((DateTime)value).ToString + "#" 
    } 
    else if (dataType == typeof(bool)) 
    { 
     return ((bool)value) ? "1" : "0"; 
    } 

    return value.ToString(); 
} 

public static void ExecuteNonQuery(string sql, OleDbConnection conn) 
{ 
    if (conn == null) 
     throw new ArgumentNullException("conn"); 

    ConnectionState prevState = ConnectionState.Closed; 
    var command = new OleDbCommand(sql, conn); 
    try 
    { 
     // the reason we are checking the prev state is for performance reasons 
     // later you might want to open the connection once for the a batch 
     // of say 500 rows or even wrap your connection in a transaction. 
     // we don't want to open and close 500 connections 
     prevState = conn.State; 
     if (prevState != ConnectionState.Open) 
      conn.Open(); 

     command.ExecuteNonQuery(); 
    } 
    finally 
    { 
     if (conn.State != ConnectionState.Closed 
      && prevState != ConnectionState.Open) 
      conn.Close(); 
    } 
} 
+0

Sono arrivato molto lontano con il mio progetto. Ho già tutte le funzionalità programmate per ottenere il file .MDB, visualizzare le informazioni e modificare le informazioni. La mia UI è già completa, ho solo bisogno di un modo per restituire queste informazioni a un file .MDB (o preferibilmente lo stesso .MDB da cui proviene) – OneShot

+0

E chiamare le istruzioni UPDATE non funzionerà per te? – bendewey

+0

Sono sicuro che lo farà. Come faccio a chiamare la dichiarazione di aggiornamento TO. Lo chiamo sulla connessione che ho fatto al file ??? – OneShot

0

In realtà esistono più formati di file con estensione .mdb. Quindi, se indovino quello sbagliato, questa sarà la risposta sbagliata. Ma sembra un problema di Microsoft Access.

Non si scrive direttamente su un file MDB. Sono criptati e compressi. Il modo più semplice per modificare un file MDB è caricarlo tramite Access e copiare le tabelle attraverso i metodi forniti.

+0

Sì, sto utilizzando il formato Microsoft Access di un file .mdb. So che non scrivo direttamente su un file MDB.Ho bisogno di un modo per inserire eventualmente nuove tabelle OPPURE generare un file .MDB con informazioni già presenti in esso (come un Dataset pieno di tabelle). – OneShot

0

Come ci si connette al database (il file mdb)? Potresti postare qualche codice di esempio? Se ci si connette a esso correttamente, qualsiasi operazione SQL che si esegue contro di essa dovrebbe essere salvata automaticamente nel database.

Quindi, dopo essersi connessi al database, è possibile eseguire SQL che creerà tabelle, inserire/aggiornare/recuperare dati, ecc. Non è consigliabile provare a creare un file .mdb a mano.

Ecco un esempio:

http://www.java2s.com/Code/CSharp/Database-ADO.net/Access.htm

+0

Vedere il mio codice pubblicato. Quindi stai dicendo se eseguo un comando SQL che cancella qualcosa che verrà mostrato nel mio file .Mdb? Potrei già averlo dove qualunque cosa faccia è salvata nel file. Non so davvero cosa sto facendo. Come posso salvare le modifiche da un Datagrid al file .MDB? – OneShot

1

Per aggiornare il file originale MDB con le modifiche apportate al DataSet (non il DataGrid, dal momento che questo è solo UI sopra il DataSet) basta usare il comando DataAdapter.Update.

Per spostare tabelle da 1 a altro è un po 'più complicato. Se la tabella non esiste già nella destinazione, è necessario crearla utilizzando un SQL CREATE statement. Quindi, DataAdapter.Fill un DataSet dalla sorgente . Passare in rassegna ogni riga e impostare lo stato su RowAdded chiamando DataRow.SetAdded. Quindi, restituirlo a un DataAdapter.Update dal database di destinazione.

EDIT: Code is on the next question....

+0

Eccellente! Se puoi semplicemente mostrarmi del codice per poter fare un esempio ... penso che lo farà. Devo ancora capire come aggiungere le modifiche apportate da DataGrid. Hai detto DataRow.SetAdded - Perché dovrei aggiungere righe quando ho bisogno di aggiungere intere tabelle? Esiste già ogni tavolo im moving. 100% sovrascrittura – OneShot

Problemi correlati