Search code examples
c#mysqldataadapter

Inserting values into a mysql database does not work as expected


I try to fill a mySQL/ MariaDB table from within C#. Reading the table and populating a dataset works.

the table structure and its keys etc. are given and cannot be changed:

CREATE TABLE `fhem`.`history` (TIMESTAMP TIMESTAMP, DEVICE varchar(32), TYPE varchar(32), EVENT varchar(512), READING varchar(32), VALUE varchar(32), UNIT varchar(32));
CREATE TABLE `fhem`.`current` (TIMESTAMP TIMESTAMP, DEVICE varchar(32), TYPE varchar(32), EVENT varchar(512), READING varchar(32), VALUE varchar(32), UNIT varchar(32));
CREATE INDEX Search_Idx ON `fhem`.`history` (DEVICE, READING, TIMESTAMP);

This is my code to connect to the database, create the sql commands and adapters, and then fill the datasets with the data from the database tables. Then i create a new datarow, fill the columns with values and add this to the DataTable of th DataSet.

    class Program
    {
        static void Main(string[] args)
        {
            MySqlConnectionStringBuilder connBuilder = new MySqlConnectionStringBuilder();

            connBuilder.Server = "ds2";
            connBuilder.Database = "fhem";
            connBuilder.UserID = "fhemdbuser";
            connBuilder.Port = 3307;
            connBuilder.Password = "!2345Abcde";
            //connBuilder.DefaultCommandTimeout = 120;
            //connBuilder.UseDefaultCommandTimeoutForEF = true;
            //connBuilder.AllowUserVariables = true;

            MySqlConnection conn = new MySqlConnection(connBuilder.ConnectionString);
            conn.Open();
            MySqlCommand selectCmdCurrent = new MySqlCommand("select `TIMESTAMP`, `DEVICE`, `TYPE`, `EVENT`, `READING`, `VALUE`, `UNIT` from current;", conn);
            MySqlCommand selectCmdCurrentTest = new MySqlCommand("select `TIMESTAMP`, `DEVICE`, `TYPE`, `EVENT`, `READING`, `VALUE`, `UNIT` from currentTest;", conn);
            MySqlCommand updateCmd = new MySqlCommand("update `currentTest` set `TIMESTAMP`=@p1,`DEVICE`=@p2,`TYPE`=@p3,`EVENT`=@p4,`READING`=@p5,`VALUE`=@p6,`UNIT`=@p7", conn);
            updateCmd.Parameters.Add("@p1", MySql.Data.MySqlClient.MySqlDbType.DateTime);
            updateCmd.Parameters.Add("@p2", MySql.Data.MySqlClient.MySqlDbType.VarString, 128);
            updateCmd.Parameters.Add("@p3", MySql.Data.MySqlClient.MySqlDbType.VarString, 128);
            updateCmd.Parameters.Add("@p4", MySql.Data.MySqlClient.MySqlDbType.VarString, 512);
            updateCmd.Parameters.Add("@p5", MySql.Data.MySqlClient.MySqlDbType.VarString, 128);
            updateCmd.Parameters.Add("@p6", MySql.Data.MySqlClient.MySqlDbType.VarString, 128);
            updateCmd.Parameters.Add("@p7", MySql.Data.MySqlClient.MySqlDbType.VarString, 128);

            MySqlCommand insertCmd = new MySqlCommand("insert into `currentTest` values(@p1, @p2, @p3, @p4, @p5, @p6, @p7)", conn);
            insertCmd.Parameters.Add("@p1", MySql.Data.MySqlClient.MySqlDbType.DateTime);
            insertCmd.Parameters.Add("@p2", MySql.Data.MySqlClient.MySqlDbType.VarString, 128);
            insertCmd.Parameters.Add("@p3", MySql.Data.MySqlClient.MySqlDbType.VarString, 128);
            insertCmd.Parameters.Add("@p4", MySql.Data.MySqlClient.MySqlDbType.VarString, 512);
            insertCmd.Parameters.Add("@p5", MySql.Data.MySqlClient.MySqlDbType.VarString, 128);
            insertCmd.Parameters.Add("@p6", MySql.Data.MySqlClient.MySqlDbType.VarString, 128);
            insertCmd.Parameters.Add("@p7", MySql.Data.MySqlClient.MySqlDbType.VarString, 128);
            MySqlDataAdapter dataAdapterCurrent = new MySqlDataAdapter(selectCmdCurrent);
            MySqlDataAdapter dataAdapterCurrentTest = new MySqlDataAdapter(selectCmdCurrentTest);
            // MySqlCommandBuilder builder = new MySqlCommandBuilder(dataAdapterCurrent);
            dataAdapterCurrentTest.InsertCommand = insertCmd;
            dataAdapterCurrentTest.UpdateCommand = updateCmd;
            DataSet ds = new DataSet();
            MySqlCommand prepareCmd = new MySqlCommand("truncate currentTest;", conn);
            prepareCmd.ExecuteNonQuery();
            //prepareCmd = new MySqlCommand("insert into currentTest select * from current;", conn);
            //prepareCmd.ExecuteNonQuery();
            prepareCmd = new MySqlCommand("INSERT INTO `currentTest` VALUES(\"2020-06-06 12:45:23\",\"DEVICE\", \"TYPE\", \"EVENT\", \"READING\", \"VALUE\", \"UNIT\")", conn);
            for (int i = 0; i < 10; i++)
                prepareCmd.ExecuteNonQuery();
            dataAdapterCurrentTest.Fill(ds, "currentTest");
            dataAdapterCurrent.Fill(ds, "current");
            int row = 0;

            Stopwatch sw = new Stopwatch();
            for (int i = 0; i < 10; i++)
            {

                DataRow newrow = ds.Tables["currentTest"].NewRow();
                newrow["Timestamp"] = DateTime.Now;
                newrow["Device"] = "Device";
                newrow["TYPE"] = "Type";
                newrow["EVENT"] = "Event";
                newrow["READING"] = "Reading";
                newrow["VALUE"] = "Value";
                newrow["UNIT"] = "Unit";
                ds.Tables["currentTest"].Rows.Add(newrow);
            }
            dataAdapterCurrentTest.Update(ds.Tables["currentTest"]);
            ds.Tables["currentTest"].AcceptChanges();
        }
    }

Whereas the manual insert command puts the correct values into the database, the programatic approach via

DataRow newrow = ds.Tables["currentTest"].NewRow();
ds.Tables["currentTest"].Rows.Add(newrow);
dataAdapterCurrentTest.Update(ds.Tables["currentTest"]);
ds.Tables["currentTest"].AcceptChanges();

only adds rows with a valid date, but the other columns are NULL.

[Edit #1] : I did some changes to my code, basically I modified the second for loop to insert new data like i did in the first loop. Then the data gets written correctly into the database. But I doubt, if it is a performant way to call .ExecuteNonQuery() several thousand times to put my log file into the database...

[Edit #2] : The 100 000 inserts into the database with .ExecuteNonQuery() are still running after 120 Minutes. This is pretty slow.


Solution

  • With MysqlDataAdapter we need to set the selectCommand only. It will generate the insertCommand automatically by MySqlCommandBuilder

    Your code is almost correct only 2 changes are required.

    1. Add following line before dataAdapterCurrentTest.Update(ds.Tables["currentTest"])

    new MySqlCommandBuilder(dataAdapterCurrentTest);
    


    2. Comment folloing line of Code

    dataAdapterCurrentTest.InsertCommand=insertCmd
    

    So the final code is

     class Program
        {
            static void Main(string[] args)
            {
                MySqlConnectionStringBuilder connBuilder = new MySqlConnectionStringBuilder();
    
                connBuilder.Server = "ds2";
                connBuilder.Database = "fhem";
                connBuilder.UserID = "fhemdbuser";
                connBuilder.Port = 3307;
                connBuilder.Password = "!2345Abcde";
                //connBuilder.DefaultCommandTimeout = 120;
                //connBuilder.UseDefaultCommandTimeoutForEF = true;
                //connBuilder.AllowUserVariables = true;
    
                MySqlConnection conn = new MySqlConnection(connBuilder.ConnectionString);
                conn.Open();
                MySqlCommand selectCmdCurrent = new MySqlCommand("select `TIMESTAMP`, `DEVICE`, `TYPE`, `EVENT`, `READING`, `VALUE`, `UNIT` from current;", conn);
                MySqlCommand selectCmdCurrentTest = new MySqlCommand("select `TIMESTAMP`, `DEVICE`, `TYPE`, `EVENT`, `READING`, `VALUE`, `UNIT` from currentTest;", conn);
                MySqlCommand updateCmd = new MySqlCommand("update `currentTest` set `TIMESTAMP`=@p1,`DEVICE`=@p2,`TYPE`=@p3,`EVENT`=@p4,`READING`=@p5,`VALUE`=@p6,`UNIT`=@p7", conn);
                updateCmd.Parameters.Add("@p1", MySql.Data.MySqlClient.MySqlDbType.DateTime);
                updateCmd.Parameters.Add("@p2", MySql.Data.MySqlClient.MySqlDbType.VarString, 128);
                updateCmd.Parameters.Add("@p3", MySql.Data.MySqlClient.MySqlDbType.VarString, 128);
                updateCmd.Parameters.Add("@p4", MySql.Data.MySqlClient.MySqlDbType.VarString, 512);
                updateCmd.Parameters.Add("@p5", MySql.Data.MySqlClient.MySqlDbType.VarString, 128);
                updateCmd.Parameters.Add("@p6", MySql.Data.MySqlClient.MySqlDbType.VarString, 128);
                updateCmd.Parameters.Add("@p7", MySql.Data.MySqlClient.MySqlDbType.VarString, 128);
    
                MySqlCommand insertCmd = new MySqlCommand("insert into `currentTest` values(@p1, @p2, @p3, @p4, @p5, @p6, @p7)", conn);
                insertCmd.Parameters.Add("@p1", MySql.Data.MySqlClient.MySqlDbType.DateTime);
                insertCmd.Parameters.Add("@p2", MySql.Data.MySqlClient.MySqlDbType.VarString, 128);
                insertCmd.Parameters.Add("@p3", MySql.Data.MySqlClient.MySqlDbType.VarString, 128);
                insertCmd.Parameters.Add("@p4", MySql.Data.MySqlClient.MySqlDbType.VarString, 512);
                insertCmd.Parameters.Add("@p5", MySql.Data.MySqlClient.MySqlDbType.VarString, 128);
                insertCmd.Parameters.Add("@p6", MySql.Data.MySqlClient.MySqlDbType.VarString, 128);
                insertCmd.Parameters.Add("@p7", MySql.Data.MySqlClient.MySqlDbType.VarString, 128);
                MySqlDataAdapter dataAdapterCurrent = new MySqlDataAdapter(selectCmdCurrent);
                MySqlDataAdapter dataAdapterCurrentTest = new MySqlDataAdapter(selectCmdCurrentTest);
                // MySqlCommandBuilder builder = new MySqlCommandBuilder(dataAdapterCurrent);
               // dataAdapterCurrentTest.InsertCommand = insertCmd;
                dataAdapterCurrentTest.UpdateCommand = updateCmd;
                DataSet ds = new DataSet();
                MySqlCommand prepareCmd = new MySqlCommand("truncate currentTest;", conn);
                prepareCmd.ExecuteNonQuery();
                //prepareCmd = new MySqlCommand("insert into currentTest select * from current;", conn);
                //prepareCmd.ExecuteNonQuery();
                prepareCmd = new MySqlCommand("INSERT INTO `currentTest` VALUES(\"2020-06-06 12:45:23\",\"DEVICE\", \"TYPE\", \"EVENT\", \"READING\", \"VALUE\", \"UNIT\")", conn);
                for (int i = 0; i < 10; i++)
                    prepareCmd.ExecuteNonQuery();
                dataAdapterCurrentTest.Fill(ds, "currentTest");
                dataAdapterCurrent.Fill(ds, "current");
                int row = 0;
    
                Stopwatch sw = new Stopwatch();
                for (int i = 0; i < 10; i++)
                {
    
                    DataRow newrow = ds.Tables["currentTest"].NewRow();
                    newrow["Timestamp"] = DateTime.Now;
                    newrow["Device"] = "Device";
                    newrow["TYPE"] = "Type";
                    newrow["EVENT"] = "Event";
                    newrow["READING"] = "Reading";
                    newrow["VALUE"] = "Value";
                    newrow["UNIT"] = "Unit";
                    ds.Tables["currentTest"].Rows.Add(newrow);
                }
    
                new MySqlCommandBuilder(dataAdapterCurrentTest);
    
                dataAdapterCurrentTest.Update(ds.Tables["currentTest"]);
                ds.Tables["currentTest"].AcceptChanges();
            }
        }