C # Problema: Qual è il modo più semplice per me per caricare un file MDB, apportare le modifiche ad esso, e salvare le modifiche al file originale?

StackOverflow https://stackoverflow.com/questions/518239

Domanda

Il mio progetto che sto lavorando è quasi finito. Sto caricando un file mdb, la visualizzazione dei contenuti su un DataGrid e il tentativo di ottenere quei cambiamenti sul DataGrid e salvarli nuovamente dentro il file mdb. Ho anche intenzione di creare una funzione che mi permette di prendere le tabelle da un file mdb e salvarlo in un altro file con estensione mdb. Naturalmente, non posso fare nulla di tutto questo se non riesco a capire come salvare le modifiche al file mdb.

Ho ricercato Google ampiamente e non ci sono risposte alla mia domanda. Mi considero un principiante in questo argomento specifico quindi per favore non fate le risposte troppo complicato - Ho bisogno il 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 faccio ad avere le modifiche apportate dal Datagrid? Sono sicuro che questo è abbastanza semplice rispondere.
  2. Ho quindi bisogno di sapere come prendere questo Datatable, inserirlo nel set di dati è venuto da allora prendere quel Dataset e riscrivere il file mdb. (Se c'è un modo solo di inserire le tabelle che sono state cambiate preferirei che.)

Grazie in anticipo, fatemi sapere se avete bisogno di ulteriori informazioni. Questa è l'ultima cosa che sto probabilmente costretta a chiedere informazioni su questo argomento ... grazie a dio.

Modifica

Il mdb sto lavorando con è un Microsoft Access Database. (ho rovinato nemmeno che ci fossero più file mdb)

So che non posso scrivere direttamente al file MDB attraverso uno StreamWriter o qualcosa, ma c'è un modo posso eventualmente generato un file mdb con le informazioni DataSet già in esso? O c'è solo un modo che io possa aggiungere tabelle in un file MDB che ho già caricato nel DataGrid. Ci deve essere un modo!

Ancora una volta, ho bisogno di un modo per fare questo a livello di codice in C #.

Modifica

D'accordo, il mio progetto è abbastanza grande, ma io uso un file di classe separato per gestire tutte le connessioni di database. So che il mio progetto e la fonte è davvero sciatta, ma ottiene il lavoro fatto. Sono solo buono come gli esempi che ho trovato su internet.

Ricordate, sto semplicemente il collegamento ad un DataGrid in un'altra forma. Fammi sapere se vuoi il mio codice dal modulo di DataGrid (non so il motivo per cui si avrebbe bisogno però). DatabaseHandling.cs gestisce 2 file con estensione mdb. Così vedrete due set di dati in là. Userò questo alla fine di prendere le tabelle da un set di dati e metterli in un altro set di dati. Ho solo bisogno di capire come salvare questi valori indietro in un file mdb.

Esiste un modo per fare questo? Ci deve essere un modo ...

Modifica

Da quello che ho studiato e letto ... Penso che la risposta è proprio sotto il mio naso. Utilizzando il comando "Update ()". Ora, mentre questo è ri-assicurando che non v'è infatti un modo semplice di fare questo, sono ancora a sinistra con il problema che non ho-friggin-idea di come utilizzare 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)"; 

Credo 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
  • Crea 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 struttura esatta, ma avranno differenti informazioni in loro.

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

Grazie ancora in anticipo.

Modifica

Va bene ... una buona notizia. Ho capito come interrogare il file mdb in sé (credo). Ecco il codice, che non funziona perché ricevo un errore di runtime a causa del comando SQL Sto tentando di usare. Il che mi porterà alla mia domanda successiva.

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 credo sia il file vero e proprio MDB Access. Come ho detto, però, la query SQL che ho eseguito su file non funziona e ha generato un errore di run-time quando viene utilizzato.

Il comando che sto cercando di eseguire dovrebbe prendere una tabella da un file mdb e sovrascrivere un tavolo dello stesso tipo di un file mdb diverso. Il comando SQL ho tentato in precedenza cercato di prendere direttamente una tabella da un file con estensione mdb, e direttamente metterla in un altro - questo non è ciò che voglio fare. Voglio prendere tutte le informazioni dal file MDB - (., Che ho fatto) ha messo le tabelle in un DataTable e quindi aggiungere tutti i DataTable a un DataSet che voglio fare questo per due file con estensione 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 >>>> ----- [Aggiungi tabelle (Sovrascriverli)] ----- >>>> DataSetB
  • DataSetB >>>> ----- [Aggiungi tabelle (Sovrascriverli)] ----- >>>> DataSetA

Voglio prendere quelle ciascuno quelle serie di dati e poi rimetterli in ciascun file di Access .MDB sono venuti. In sostanza mantenendo entrambi i database sincronizzati.

Quindi le mie domande, rivisti, è:

  1. Come faccio a creare 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 creare in modo dinamico durante l'esecuzione di una serie che sostituisce una variabile con il nome della tabella voglio aggiungere.
  2. Come faccio a ottenere le modifiche che sono state fatte dal DataGrid a DataTable e riporli in un DataTable (o DataSet) in modo che io possa inviare al file mdb?

Ho cercato di elaborare il più possibile ... perché credo non sto explaing mio problema molto bene. Ora questa domanda è cresciuta wayyy troppo a lungo. Vorrei solo che avrei potuto spiegare questo meglio. : [

Modifica

Grazie a un utente sotto Credo di aver quasi trovato una soluzione - la parola quasi . Ecco il mio codice DatabaseHandling.cs aggiornata qui sotto. Ottengo un errore di runtime "Tipo di dati non corrispondente." Non so come questo potrebbe essere possibile, considerando che sto cercando di copiare queste tabelle in un altro database con la stessa impostazione.

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é mi appare questo errore? Entrambe le tabelle sono esattamente gli stessi. Che cosa sto facendo di sbagliato? Nel peggiore dei casi, come faccio a cancellare la tavola in un altro file di Access mdb prima di inserire la stessa tabella esatta struttura con diversi valori in esso?

L'uomo Vorrei poter solo questo numero ...

Modifica

Va bene, sono venuto una certa distanza. La mia domanda è trasformato in uno nuovo, e quindi merita di essere chiesto separatamente. Ho avuto la mia domanda ha risposto, come ora so come eseguire le query direttamente alla connessione che ho aperto. Grazie a tutti!

È stato utile?

Soluzione

Non sono sicuro di quanto lontano che hai ottenuto, ma se si cerca di una rapida operazione di trascinamento si potrebbe desiderare di guardare alla creazione di un dataset fortemente tipizzato che collega, e utilizzando le funzionalità di trascinamento della DataSources finestra strumento in Visual Studio.

Ci sono campioni definately là fuori, ma si vorranno.

  1. Crea un nuovo DataSet
  2. drag-n-drop dal tuo DataConnection Albero in Esplora server
  3. Crea un nuovo modulo
  4. Trascinare la tabella dallo 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 alcune LinkTables tra i file di accesso che sarebbe meglio, allora è possibile copiare i dati tra file utilizzando un'istruzione SQL come 'INSERT INTO clienti a scegliere Nome, Cognome FROM File2.Customers'. Se quello non e un'opzione Credo che la vostra intenzione di avere a ciclo le DataTable e inserire i record utilizzando manualmente le istruzioni INSERT simili alla tua ultima modifica. Per quanto riguarda il datagrid, probabilmente si dovrà tenere traccia di che cosa è cambiato dal monitoraggio della RowChanged evento (non so se questo è l'evento esatto) anche di fare le dichiarazioni di inserimento / aggiornamento quando cambia la riga.

Aggiornamento:

per ciclo DataTable si dovrebbe fare qualcosa di simile. non testato. Ho appena aggiornato di nuovo questo per includere la funzione MakeValueDbReady. Questo non è testato né e non sono sicuro se ho gestire tutti i casi o anche tutti i casi in modo corretto. Avrete davvero necessario eseguire il debug l'istruzione SQL e assicurarsi che la sua generazione il giusto valore. Ogni database gestisce è valori in modo diverso. Atleast questo modo il valore di analisi viene estratto via. 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();
    }
}

Altri suggerimenti

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 le tabelle da 1 a l'altro è un po 'più complicato. Se la tabella non esiste già nella destinazione, è necessario crearla utilizzando un SQL CREATE . Poi, DataAdapter.Fill un DataSet dalla fonte . Ciclicamente ogni riga e impostare suo stato di RowAdded chiamando DataRow.SetAdded . Poi, passa di nuovo ad un DataAdapter.Update dal database destinazione .

EDIT: Codice è sul domanda successiva ....

Non ci sono in realtà più di un formato di file con estensione mdb. Quindi, se io immagino quello sbagliato, questa sarà la risposta sbagliata. Ma, suona come un problema di Microsoft Access.

Non scrivere direttamente in un file MDB. Essi sono criptati e compressi. Il modo più semplice per modificare un file MDB è quello di caricarlo tramite Access e copiare le tabelle con i metodi a disposizione.

Come vi state collegando al database (il file mdb)? Potresti postare alcuni esempi di codice? Se ci si collega ad esso in modo corretto di qualsiasi operazioni SQL si esegue contro di essa deve essere salvato nel database automaticamente.

Quindi, dopo la connessione al database è possibile eseguire SQL che creerà le tabelle, inserimento / aggiornamento / recuperare i dati, ecc Cercando di creare un file mdb a mano non è consigliabile.

Ecco un esempio:

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

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top