2009-02-05 8 views
5

Mi proyecto en el que estoy trabajando está casi terminado. Estoy cargando un archivo .MDB, mostrando los contenidos en un DataGrid e intentando obtener esos cambios en el DataGrid y guardarlos nuevamente en el archivo .MDB. También voy a crear una función que me permita tomar las tablas de un archivo .MDB y guardarlo en otro archivo .MDB. Por supuesto, no puedo hacer nada de esto si no puedo encontrar la forma de guardar los cambios en el archivo .MDB.C# Problema: ¿Cuál es la forma más sencilla de cargar un archivo .MDB, realizar cambios en él y guardar los cambios nuevamente en el archivo original?

He investigado extensamente en Google y no hay respuestas a mi pregunta. Me considero un principiante en este tema específico, así que no hagas las respuestas demasiado complicadas. ¡Necesito la forma más sencilla de editar un archivo .MDB! Proporcione ejemplos de programación.

  1. Supongamos que ya he hecho una conexión a un DataGrid. ¿Cómo obtengo los cambios realizados por Datagrid? Estoy seguro de que este es lo suficientemente simple para responder.
  2. Necesito saber cómo tomar esta tabla de datos, insertarla en el conjunto de datos de donde vino, tomar ese conjunto de datos y volver a escribir el archivo .MDB. (Si hay una forma de insertar solamente las tablas que se cambiaron, lo preferiría).

Gracias de antemano, avíseme si necesita más información. Esto es lo último que probablemente tenga que preguntar sobre este tema ... gracias a Dios.

EDIT:

El .mdb estoy trabajando con una base de datos Microsoft Access . (Ni siquiera sabía que había varios archivos .mdb)

Sé que no puedo escribir directamente en el archivo .MDB a través de un secuenciador de secuencias o algo así, pero ¿hay alguna manera de que pueda generar un archivo .MDB con la información del conjunto de datos? Ya en ella? O simplemente hay una manera en que puedo agregar tablas a un archivo .MDB que ya he cargado en DataGrid. ¡TIENE que haber una manera!

Una vez más, necesito una manera de hacer esto mediante programación en C#.

EDIT:

bien, mi proyecto es bastante grande, pero yo uso un archivo de clase independiente para manejar todas las conexiones de base de datos. Sé que mi diseño y fuente son muy descuidados, pero hacen el trabajo bien. Solo soy tan bueno como los ejemplos que encuentro en internet.

Recuerde, simplemente me estoy conectando a un DataGrid en otra forma. Avíseme si quiere mi código del formulario Datagrid (no sé por qué lo necesitaría). DatabaseHandling.cs maneja 2 archivos .MDB. Entonces verás dos conjuntos de datos allí. Usaré esto eventualmente para tomar tablas de un Dataset y ponerlas en otro Dataset. Solo necesito averiguar cómo guardar estos valores BACK en un archivo .MDB.

¿Hay alguna forma de hacerlo? Tiene que haber una manera ...

EDIT:

Por lo que he investigado y leído ... Creo que la respuesta está justo debajo de la nariz. Usando el comando "Actualizar()".Ahora bien, aunque esto asegura que hay una manera simple de hacerlo, todavía me queda el problema de que no tengo idea de cómo usar este comando de actualización.

Tal vez pueda configurarlo de la siguiente manera:

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)"; 

Creo que puede hacerlo, pero no quiero insertar manualmente nada. Quiero hacer ambas cosas en su lugar:

  • tomar la información que se cambia en la cuadrícula de datos y actualizar el archivo de base de Access (.mdb) que yo tengo de
  • Crear una función que me permite tomar las tablas desde otro archivo de base de datos de acceso (.mdb) y reemplazarlos en un archivo de base de datos de acceso secundario (.mdb). Ambos archivos usarán la misma estructura pero tendrán diferente información en ellos.

Espero que alguien encuentre una respuesta para esto ... mi proyecto está hecho, todo lo que le espera es una respuesta simple.

Gracias de nuevo con antelación.

EDIT:

bien ... buenas noticias. He descubierto cómo consultar el archivo .mdb en sí (creo). Aquí está el código, que no funciona porque recibo un error de tiempo de ejecución debido al comando sql que estoy intentando usar. Lo cual me llevará a mi próxima pregunta.

nuevo código de función añadida a 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(); 
} 

Como se puede ver, de hecho he conseguido ejecutar una consulta en la conexión en sí, que creo que es el acceso real. Archivo MDB. Sin embargo, como dije, la consulta SQL que he ejecutado en el archivo no funciona y generó un error en tiempo de ejecución cuando se usa.

Se supone que el comando que estoy intentando ejecutar toma una tabla de un archivo .MDB y sobrescribe una tabla del mismo tipo de un archivo .MDB diferente. El comando SQL que intenté anteriormente intentó tomar directamente una tabla de un archivo .mdb y ponerla directamente en otro; esto no es lo que quiero hacer. Quiero tomar toda la información del archivo .MDB - poner las tablas en una tabla de datos y luego agregar todas las tablas de datos a un conjunto de datos (que he hecho). Quiero hacer esto para dos archivos .MDB. Una vez que tengo dos conjuntos de datos que desee tomar las tablas específicas de cada conjunto de datos y añadirlos a cada archivo de la siguiente manera:

  • DataSetA >>>> ----- [Agregar tablas (sobrescribir)] - ---- >>>> DataSetB
  • DataSetB >>>> ----- [Agregar tablas (sobrescribir)] ----- >>>> DataSetA

quiero tomar esos cada uno de esos conjuntos de datos y luego ponerlos de nuevo en cada archivo de acceso .MDB de donde vinieron. Esencialmente mantener ambas bases de datos sincronizadas.

Así que mis preguntas, revisada, es:

  1. ¿Cómo se crea una consulta SQL que añadirá una tabla en el archivo MDB al sobrescribir el existente del mismo nombre.La consulta debería poder crearse dinámicamente durante el tiempo de ejecución con una matriz que reemplaza una variable con el nombre de la tabla que deseo agregar.
  2. ¿Cómo obtengo los cambios que realizó Datagrid en DataTable y los vuelvo a poner en una DataTable (o DataSet) para poder enviarlos al archivo .MDB?

He tratado de elaborar lo más posible ... porque creo que no estoy explicando mi problema muy bien. Ahora esta pregunta ha crecido muchísimo demasiado. Solo desearía poder explicar esto mejor. : [

EDIT:

Gracias a un usuario a continuación creo que casi he encontrado una solución - la palabra clave casi. Aquí está mi código actualizado de DatabaseHandling.cs a continuación. Obtengo un error de tiempo de ejecución "Datatype Mismatch". No sé cómo podría ser posible teniendo en cuenta que estoy tratando de copiar estas tablas en otra base de datos con la misma configuración.

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(); 
       } 
      } 

      }   
     } 

¿Por qué me aparece este error? Ambas tablas son exactamente lo mismo. ¿Qué estoy haciendo mal? Peor caso, ¿cómo elimino la tabla en el otro archivo .MDB de Access antes de insertar exactamente la misma tabla de estructura con diferentes valores en ella?

hombre que desearía poder resolver esto ...

EDIT:

bien, he llegado a cierta distancia. Mi pregunta se transformó en una nueva, y por lo tanto, merece ser preguntado por separado. Me respondieron mi pregunta porque ahora sé cómo ejecutar consultas directamente a la conexión que abrí. ¡Gracias a todos!

+0

@Remou: tratando de llamar su atención aquí - usted está haciendo una mala situación peor. Acceso! = MDB. Todas estas preguntas que está volviendo a etiquetar de MDB a MS-ACCESS no implican acceso en absoluto, sino solo el motor de base de datos Jet/ACE. Estoy volviendo a etiquetar en consecuencia. –

+0

@Remou @David W. Fenton: He planteado este problema en meta: http://meta.stackoverflow.com/questions/33216/ms-access-or-mdb-or-access-database-engine-or- ms-jet-ace – onedaywhen

+0

Ya publiqué en Meta. MDB también es igual a los beans controlados por mensajes, por lo que es una etiqueta ambigua, y al igual que Access, que está etiquetado como ms-access debido a la ambigüedad, debe cambiar. – Fionnuala

Respuesta

3

No estoy seguro de lo lejos que ha llegado, pero si busca una operación rápida de arrastrar y soltar, puede considerar crear un conjunto de datos fuertemente tipado que se conecte y usar las funciones de arrastrar y soltar de la ventana de la herramienta DataSources en Visual Studio.

Definitivamente hay muestras, pero querrá hacerlo.

  1. Crear un nuevo conjunto de datos
  2. Arrastrar y soltar desde su árbol de DataConnection en el Explorador de servidores
  3. Crear una nueva forma
  4. Arrastre la tabla desde la herramienta DataSources
  5. ventana a la forma .
  6. voila

Actualización:

En primer lugar, no estoy 100% que entiendo su problema. Si puede crear algunas tablas de enlaces entre los archivos de acceso que serían las mejores, entonces puede copiar los datos entre archivos utilizando una instrucción sql como 'INSERT INTO Customers SELECT FirstName, LastName FROM File2.Customers'. Si eso no es así, y la opción, creo que va a tener que hacer un bucle en las tablas de datos e insertar los registros manualmente usando instrucciones INSERT similares a su última edición. En cuanto a la cuadrícula de datos, probablemente tendrá que hacer un seguimiento de lo que cambió al monitorear el evento RowChanged (no estoy seguro si ese es el evento exacto) de incluso hacer las instrucciones de inserción/actualización cuando la fila cambie.

Actualización:

al bucle de la tabla de datos que haría algo como esto. no probado. Acabo de actualizar esto de nuevo para incluir la función MakeValueDbReady. Esto tampoco se ha probado y no estoy seguro de haber manejado todos los casos o incluso todos los casos correctamente. Realmente tendrá que depurar la declaración sql y asegurarse de que está generando el valor correcto. Cada base de datos maneja los valores de manera diferente. Al menos de esta manera, el análisis de valor se extrae. También me di cuenta de que en lugar de codificar duro el NombreTabla usted debería ser capaz de obtener de una propiedad en la 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

He llegado muy lejos con mi proyecto. Ya tengo toda la funcionalidad programada para obtener el archivo .MDB, mostrar la información y cambiar la información. Mi interfaz de usuario ya está completa, solo necesito una forma de devolver esta información A un archivo .MDB (o preferiblemente el mismo .MDB del que proviene) – OneShot

+0

¿Y al invocar las instrucciones UPDATE no funcionará para usted? – bendewey

+0

Estoy seguro de que así será. ¿A qué llamo la declaración de actualización TO? ¿Lo llamo en la conexión que he hecho al archivo? – OneShot

0

En realidad, hay más de un formato de archivo con la extensión .mdb. Entonces, si adivino el equivocado, esta será la respuesta incorrecta. Pero suena como un problema de Microsoft Access.

No escribe directamente en un archivo MDB. Están encriptados y comprimidos. La forma más fácil de modificar un archivo MDB es cargarlo a través de Access y copiar las tablas a través de los métodos provistos.

+0

Sí, estoy usando el formato Microsoft Access de un archivo .mdb. Sé que no escribo directamente en un archivo MDB.Necesito una manera de posiblemente insertar nuevas tablas O generar un archivo .MDB con información que ya está en él (como un Dataset lleno de tablas). – OneShot

0

¿Cómo se conecta a la base de datos (el archivo .mdb)? ¿Podría publicar un código de muestra? Si se está conectando a él correctamente, las operaciones de SQL que ejecute se deberían guardar automáticamente en la base de datos.

Entonces, después de conectarse a la base de datos, puede ejecutar SQL que creará tablas, insertará/actualizará/recuperará datos, etc. Intentar construir un archivo .mdb a mano no es aconsejable.

He aquí un ejemplo:

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

+0

Vea el código publicado. Entonces, ¿está diciendo que si ejecuto un comando SQL que elimine algo que se mostrará en mi archivo .Mdb? Puede que ya lo tenga donde todo lo que hago se guarda en el archivo. Realmente no sé lo que estoy haciendo. Sin embargo, ¿cómo podría guardar los cambios de una cuadrícula de datos en el archivo .MDB? – OneShot

1

Para actualizar el archivo MDB original con los cambios realizados en el conjunto de datos (no la cuadrícula de datos, ya que eso es sólo la interfaz de usuario sobre el conjunto de datos) sólo tiene que utilizar el comando DataAdapter.Update.

Mover las tablas de 1 a la otra es un poco más complicado. Si la tabla aún no existe en el destino, deberá crearla usando un SQL CREATE statement. Luego, DataAdapter.Fill un DataSet de la fuente . Pasa por cada fila y configura su estado en RowAdded llamando al DataRow.SetAdded. A continuación, páselo a DataAdapter.Update desde la base de datos de destino.

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

+0

¡Excelente! Si puede mostrarme un código para que pueda obtener un ejemplo ... Creo que eso lo hará. Todavía necesito descubrir cómo agregar los cambios realizados por DataGrid. Usted dijo DataRow.SetAdded - ¿Por qué debería agregar filas cuando necesito Agregar tablas completas? Cada tabla que estoy moviendo ya existe. 100% sobrescrito – OneShot

Cuestiones relacionadas