views:

2570

answers:

3

I am trying to take tables from one Access Database File, add them to another Access Database file with the exact same structure but with different information. I need to overwrite any existing tables. I am almost done with my project this is last my brick wall.

I am using a separate class file named DatabaseHandling.cs to work with the Access Database files.

Here is my ENTIRE current DatabaseHandling.cs code. This is kept up to date for now on.

Code:

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

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!", true, false, false);
            }

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

            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!", true, false, false);
            }



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

            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...");
            Logging.updateLog("Started Loading File A", false, true, false);
            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);
                }
            }
            Logging.updateLog("Finished loading File A", false, true, false);
            Logging.updateLog("Started loading File B", false, true, false);
            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);
                }
            }
            Logging.updateLog("Finished loading File B", false, true, false);


        }

        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)
                {
                    OverwriteTable(table, table.TableName);
                    Logging.updateLog("Copied " + table.TableName + " successfully.", false, true, false);
                }

        }

        static void OverwriteTable(DataTable sourceTable, string tableName)
        {
            using (var destConn = new OleDbConnection(connectionstringA))
            using (var destCmd = new OleDbCommand(tableName, destConn) { CommandType = CommandType.TableDirect })
            using (var destDA = new OleDbDataAdapter(destCmd))
            {
                // Since we're using a single table, we can have the CommandBuilder
                // generate the appropriate INSERT and DELETE SQL statements
                using (var destCmdB = new OleDbCommandBuilder(destDA))
                {
                    destCmdB.QuotePrefix = "["; // quote reserved column names
                    destCmdB.QuotePrefix = "]";
                    destDA.DeleteCommand = destCmdB.GetDeleteCommand();
                    destDA.InsertCommand = destCmdB.GetInsertCommand();

                    // Get rows from destination, and delete them
                    var destTable = new DataTable();
                    destDA.Fill(destTable);
                    foreach (DataRow dr in destTable.Rows)
                    {
                        dr.Delete();
                    }
                    destDA.Update(destTable);

                    // Set rows from source as Added, so the DataAdapter will insert them
                    foreach (DataRow dr in sourceTable.Rows)
                    {
                        dr.SetAdded();
                    }
                    destDA.Update(sourceTable);
                }
            }
        }



        }          
    }

I simply want to take a Datatable that is in memory and write it to a .MDB file. I have been attempting to do this for over 30 hours.

LATEST EDIT:

Okay, added new code. I get a new run-time error: Syntax error in FROM clause.

Code:

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

        foreach (DataTable table in tablesA.Tables)
        {
            OverwriteTable(table, table.TableName);
            Logging.updateLog("Copied " + table.TableName + " successfully.", false, true, false);
        }

}

static void OverwriteTable(DataTable sourceTable, string tableName)
{
    using (var destConn = new OleDbConnection(connectionstringA))
    using (var destCmd = new OleDbCommand(tableName, destConn) { CommandType = CommandType.TableDirect })
    using (var destDA = new OleDbDataAdapter(destCmd))
    {
        // Since we're using a single table, we can have the CommandBuilder
        // generate the appropriate INSERT and DELETE SQL statements
        using (var destCmdB = new OleDbCommandBuilder(destDA))
        {
            destCmdB.QuotePrefix = "["; // quote reserved column names
            destCmdB.QuotePrefix = "]";
            destDA.DeleteCommand = destCmdB.GetDeleteCommand();
            destDA.InsertCommand = destCmdB.GetInsertCommand();

            // Get rows from destination, and delete them
            var destTable = new DataTable();
            destDA.Fill(destTable);
            foreach (DataRow dr in destTable.Rows)
            {
                dr.Delete();
            }
            destDA.Update(destTable);

            // Set rows from source as Added, so the DataAdapter will insert them
            foreach (DataRow dr in sourceTable.Rows)
            {
                dr.SetAdded();
            }
            destDA.Update(sourceTable); // !!! Run-time error: Syntax error in FROM clause. !!!
        }
    }
}

Once again, it does not work. Let me know if you need additional information.

+1  A: 

I get the feeling you're not really grokking the whole DataTable/DataRow thing. You see, in a database, you don't really work with tables - but with rows. If you want to "overwrite" TableB with TableA's rows, you'd first delete all of the rows in TableB and then insert copies of all the rows from TableA.

Assuming the destination table already exists, you can do the insert by filling from 1 source, and then setting the rows to Added. The DataAdapter will then run a SQL insert command for each added row.

static void CopyTable(string sourceConnectionString, string destinationConnectionString, string tableName) {
    // Get rows from source
    var sourceTable = new DataTable();
    using (var sourceConn = new OleDbConnection(sourceConnectionString))
    using (var sourceCmd = new OleDbCommand(tableName, sourceConn) { CommandType = CommandType.TableDirect })
    using (var sourceDA = new OleDbDataAdapter(sourceCmd)) {
        sourceDA.Fill(sourceTable);
    }

    OverwriteTable(sourceTable, destinationConnectionString, tableName);
}

static void OverwriteTable(DataTable sourceTable, string destinationConnectionString, string tableName) {
    using (var destConn = new OleDbConnection(destinationConnectionString))
    using (var destCmd = new OleDbCommand(tableName, destConn) { CommandType = CommandType.TableDirect })
    using (var destDA = new OleDbDataAdapter(destCmd)) {
        // Since we're using a single table, we can have the CommandBuilder
        // generate the appropriate INSERT and DELETE SQL statements
        using (var destCmdB = new OleDbCommandBuilder(destDA)) {
            destCmdB.QuotePrefix = "["; // quote reserved column names
            destCmdB.QuoteSuffix = "]";
            destDA.DeleteCommand = destCmdB.GetDeleteCommand();
            destDA.InsertCommand = destCmdB.GetInsertCommand();

            // Get rows from destination, and delete them
            var destTable = new DataTable();
            destDA.Fill(destTable);
            foreach (DataRow dr in destTable.Rows) {
                dr.Delete();
            }
            destDA.Update(destTable);

            // Set rows from source as Added, so the DataAdapter will insert them
            foreach (DataRow dr in sourceTable.Rows) {
               dr.SetAdded(); 
            }
            destDA.Update(sourceTable);
        }
    }    
}

EDIT: Split the OverwriteTable to a different method to accomodate your in memory data table. Also added quotes around generated Sql statements for your reserved Year and Month column names. Moved dispose of CommandBuilder as fixed by bendewey.

Mark Brackett
Thank you for your response. I did NOT know that I had to do it row by row. I copied and pasted your code and ran it to see if it worked and I got a run-time error: "Update requires a valid DeleteCommand when passed DataRow collection with deleted rows." What am I doing wrong?
OneShot
I need to know how to take a DataTable I already have in memory and THEN overwrite the Access Database file table. Not take a table from directly from a .MDB file and adding it directly to another .MDB file. Do you see what i'm saying? How do I do that?
OneShot
Just don't do the fetch from source...I split the code to 2 methods for you.
Mark Brackett
Thanks -- ill see if it works. If it does, my god I wont know how to thank you or the other guy helping me. Quick question...the Compiler can't find this destDA.QuotePrefix or destDA.QuoteSuffix. Are you sure that is what you mean, cause that isn't working?
OneShot
Nope...I misttyped (and didn't test). It's supposed to be destCmdB.Quote*. Fixed.
Mark Brackett
Hey, check my post. I cleaned it up and added a new EDIT to it. Im getting a run-time error with your code
OneShot
+1  A: 

Try replacing

using (var destCmdB = new OleDbCommandBuilder(destDA)) 
{            
    destDA.DeleteCommand = destCmdB.GetDeleteCommand();            
    destDA.InsertCommand = destCmdB.GetInsertCommand();        
}

with

destDA.InsertCommand = new OleDbCommand("INSERT INTO `AdminUsers` (`UserName`, `Password`) VALUES (?, ?)");
destDA.DeleteCommand = new OleDbCommand("DELETE FROM `AdminUsers` WHERE (`ID` = ?)");
destDA.UpdateCommand = new OldDbCommand("UPDATE `AdminUsers` SET `UserName` = ?, `Password` = ? WHERE (`ID` = ?)");

Where the queries are valid to your table structure.

bendewey
Thank you! This may work, but how do I find out what is valid to my table structure? I swear to god if you fix this I will be indebted to you.
OneShot
When I paste that in there, I get a compiler error: Cannot implicitly convert type 'string' to 'System.Data.OleDb.OleDbCommand'. I am sorry I am being so newby...but I just need to see one good example that WORKS and ill always remember how to do it!
OneShot
My faulted add a new OleDbCommand() around the string
bendewey
Whats your table look like? Do you know ahead of time? Does it change? or vary at runtime?
bendewey
How can I show you what my table looks like? There are two Access Databases. Same structure EVERY time. All I am doing is changing information some information in the cells. The structure does NOT change. Yes I know ahead of time what the structure looks like. Let me know, ill do w/e u want.
OneShot
Check my new edit
OneShot
Do you have a windows live account? they have an app called SkyDrive that's free and you can post your MDB file in your public folder and post the link here
bendewey
change your declaration one more time to new OldDbCommand("UPDATE....", conn)
bendewey
If you don't do SkyDrive you can post the MDB file somewhere on the internet and send a link with the comment.
bendewey
Okay I will. And again, Thank you for what you are doing. I am writing this program for my church and I want it to work :]. Give me a sec to upload
OneShot
http://files.filefront.com/STAFFMDB/;13220887;/fileinfo.html -- I used filefront I hope that doesn't matter. Let me know what you find out i'll be waiting impatiently :).
OneShot
Alright I'm going to shift gears on you. After testing @Mark Brackett code it turns out that this is you better bet, but there is one change. I'm going to make a new answer for it.
bendewey
Any new updates???
OneShot
+1  A: 

@Mark Brackett had it really close the reason your getting the no DeleteCommand is because the OleDbCommandBuilder is disposing so move that bracket and you should be good.

static void CopyTable(string sourceConnectionString, string destinationConnectionString, string tableName)
{
// Get rows from source    
var sourceTable = new DataTable();
using (var sourceConn = new OleDbConnection(sourceConnectionString))
using (var sourceCmd = new OleDbCommand(tableName, sourceConn) {CommandType = CommandType.TableDirect})
using (var sourceDA = new OleDbDataAdapter(sourceCmd))
{
    sourceDA.Fill(sourceTable);
}
using (var destConn = new OleDbConnection(destinationConnectionString))
using (var destCmd = new OleDbCommand(tableName, destConn) {CommandType = CommandType.TableDirect})
using (var destDA = new OleDbDataAdapter(destCmd))
{
    // Since we're using a single table, we can have the CommandBuilder        
    // generate the appropriate INSERT and DELETE SQL statements        
    using (var destCmdB = new OleDbCommandBuilder(destDA))
    {
        destDA.DeleteCommand = destCmdB.GetDeleteCommand();
        destDA.InsertCommand = destCmdB.GetInsertCommand();

        // Get rows from destination, and delete them        
        var destTable = new DataTable();
        destDA.Fill(destTable);
        foreach (DataRow dr in destTable.Rows)
        {
            dr.Delete();
        }
        destDA.Update(destTable);
        // Set rows from source as Added, so the DataAdapter will insert them        
        foreach (DataRow dr in sourceTable.Rows)
        {
            dr.SetAdded();
        }
        destDA.Update(sourceTable);
    }
}

Update

Try this exception code

static public void InitiateCopyProcessA()
{
    DataSet tablesA;
    tablesA = DatabaseHandling.getDataSetA();
    int i = 0;
    string tableName = "";
    try
    {
        foreach (DataTable table in tablesA.Tables)
        {
            tableName = table.TableName;  // for debugging the exception
            CopyTable(connectionstringA, connectionstringB, table.TableName);
        }
    }
    catch(Exception ex)
    {
        throw new Exception("Error updating " + tableName, ex);
    }
}

update

try changing

// Set rows from source as Added, so the DataAdapter will insert them                
foreach (DataRow dr in sourceTable.Rows)        
{            
    dr.SetAdded();        
}

to

// only add the first row.
sourceTable.Rows[0].SetAdded()

I'm tempted to know if its just one row that;s throwing the bug or if its the query. My thought is that one of the rows has a funky value

bendewey
Tried that, almost worked then I get a run-time error: Syntax error in INSERT INTO statement.
OneShot
How many rows are you testing? try testing only 1 row. Also set a break point and hover over the destDA.InsertCommand and see what its CommandText is. post that in your question.
bendewey
Okay I did what you said. I wasn't to sure about what you meant on testing only one row but I think I did what you asked. Let me know what you think. And thank you again for this I am so very appreciative.
OneShot
You're going to have to put some sort of logic in there to determine which table is crapping out on you. See my updated sample
bendewey
GREAT Idea. The Table that was crapping out on me was " Error updating AccountBudget" What the heck is wrong with AccountBudget???
OneShot
Do you have any ideas on what to do about it?
OneShot
Whats you inner exception say? does it still say syntax error?
bendewey
Hey, sorry went to eat. Yes, my inner exception still says " {"Syntax error in INSERT INTO statement."} "
OneShot
can you update your post with the insertcommand for the AccountBudget table
bendewey
Happy to! Its updated. I thank you again for this, from the bottom of my heart lol
OneShot
I am comparing each INSERT INTO statement. They are doing the same thing. Listening the names, and for the values how many value columns there are. Account is successfully copied, but then when it gets to AccountBudget it gives me an error. TOTALLY puzzling.
OneShot
added an update to my answer
bendewey
Okay I did what you said. Check my post for update
OneShot
I've been researching it. I have no clue what the problem is. Want to start a new question on just this specific issue?
OneShot
I'm working on it now.
bendewey
This guy below me posted code, and says it is a fix. Im just about to test it.
OneShot
found your error. Year and Month are not valid
bendewey
That shouldn't be too hard to fix right? I tried that guys code below, didn't work either.
OneShot
I think once again, this has kinda went away from the topic. I am thinking about asking a question about why I am getting errors for my SQL queries. This question kinda died and I don't blame you if you are losing interest.
OneShot
Im going to start another question specifically on my new problem
OneShot