Laden...

Service für Datenaustausch zwischen MySQL und MSSQL

Erstellt von freakontour vor 4 Jahren Letzter Beitrag vor 4 Jahren 1.348 Views
F
freakontour Themenstarter:in
15 Beiträge seit 2015
vor 4 Jahren
Service für Datenaustausch zwischen MySQL und MSSQL

verwendetes Datenbanksystem: MySQL und MS SQL

Ich habe einen Service-Dienst in C# geschrieben der Daten aus einer MySQL in eine MS SQL-Tabelle geschrieben. Der Aufruf und Abruf der Daten klappt ohne Probleme aber jedoch habe ich ein Problem im Ablauf. Wenn ich den Dienst über "Prozess anhängen" debugge läuft dieser nicht der Reihenfolge nach durch sondern springt zwischen den Methoden. Ich habe keine Aufrufe aber trotzdem wird beim Debuggen dies durchgeführt. Auch wird nur einmal die Insert-Methode aufgerufen aber ich finde mehrere doppelte Einträge in der Ziel-Tabelle.

Kann mir einer mein Problem erklären.

Service-Class:


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
using System.Threading;

namespace EOL_Service_Basis
{
    public partial class EOLService : ServiceBase
    {
        private System.Timers.Timer aTimer;
        private DataExchange dataEx;
        
        public EOLService()
        {
            InitializeComponent();
        }

        public static void Main(string[] args) 
        {
            System.ServiceProcess.ServiceBase.Run(new EOLService());
        }

        protected override void OnStart(string[] args)
        {
            SetTimer();
            dataEx.StartServer();

        }

        protected override void OnStop()
        {
            dataEx.StopServer();
        }

        public void SetTimer()
        {
            // Create a timer with a two second interval.
            aTimer = new System.Timers.Timer(10000);
            // Hook up the Elapsed event for the timer. 
            aTimer.Elapsed += OnTimedEvent;
            aTimer.AutoReset = true;
            aTimer.Enabled = true;
            dataEx = new DataExchange();
        }

        public void OnTimedEvent(Object source, ElapsedEventArgs e)
        {
            dataEx.StartExchange();
        }

    }
}

Datenaustausch-Class


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MySql.Data.MySqlClient;
using System.Data.Common;
using System.Data.SqlClient;
using System.Timers;

namespace EOL_Service_Basis
{
    class DataExchange
    {
        static Logging log = new Logging();
        static string eol = "327-GETR-EOL---";
        static int a = 1000;
        static int b = 12;


        public void StartServer()
        {
            log.createLog(eol + "Dienst wurde gestart " + DateTime.Now);
        }
        
        public void StartExchange()
        {

            
            string[,] mySqlData = new string[a, b];
            int rowsAffected;

            mySqlData = QueryEolData();
            if (mySqlData[0, 0] == null)
            {
                log.createLog(eol + "Keine Daten vorhanden");
                return;
            }
            rowsAffected = InsertSql(mySqlData);
            UpdateMySQL(mySqlData);

            if (rowsAffected > 0)
            {
                log.createLog(eol + "Success: " + rowsAffected + " Rows inserted on SQL03");
            }
        }

        public void StopServer()
        {
            log.createLog(eol + "Dienst wurde beendet: " + DateTime.Now);

        }

        private static string[,] QueryEolData()
        {
            MySqlConnection connMySql = MySQLInfo.GetDBConnection();
            MySqlCommand cmdMySQL = connMySql.CreateCommand();

            string sqlSelect = "SELECT * FROM tbl_prod_check_getr WHERE Copyed_SQL IS NULL  order by ID asc LIMIT " + a;

            string[,] mySqlData = new string[a, b];
            int i = 0;
            int v = 1;
            
            cmdMySQL.Connection = connMySql;
            cmdMySQL.CommandText = sqlSelect;
            connMySql.Open();

            MySqlDataReader reader = cmdMySQL.ExecuteReader();

            {
                if (reader.HasRows)
                {
                    try
                    {
                        while (reader.Read())
                        {
                            mySqlData[i, 0] = Convert.ToString(reader.GetValue(0));
                            mySqlData[i, 1] = Convert.ToString(reader.GetValue(1));
                            mySqlData[i, 2] = Convert.ToString(reader.GetValue(2));
                            mySqlData[i, 3] = Convert.ToString(reader.GetValue(3));
                            mySqlData[i, 4] = Convert.ToString(reader.GetValue(4));
                            mySqlData[i, 5] = Convert.ToString(reader.GetValue(5));
                            mySqlData[i, 6] = Convert.ToString(reader.GetValue(6));
                            mySqlData[i, 7] = Convert.ToString(reader.GetValue(7));
                            mySqlData[i, 8] = Convert.ToString(reader.GetValue(8));
                            mySqlData[i, 9] = Convert.ToString(reader.GetValue(9));
                            mySqlData[i, 10] = Convert.ToString(reader.GetValue(10));
                            mySqlData[i, 11] = Convert.ToString(reader.GetValue(11));

                            i++;

                        }

                        if (i == a)
                        {
                            i -= v;
                        }

                        if (mySqlData[i, 0] == null)
                        {
                            string[,] changeArray = new string[i, b];
                            for (int j = 0; j < i; j++)
                            {
                                for (int k = 0; k < b; k++)
                                {
                                    changeArray[j, k] = mySqlData[j, k];
                                }
                            }
                            return changeArray;

                        }
                        return mySqlData;
                    }
                    catch (Exception er)
                    {
                        log.createLog(eol + "ERROR  " + er.ToString());
                        return mySqlData;
                    }
                    finally
                    {
                        reader.Dispose();
                        connMySql.Close();
                        connMySql.Dispose();
                    }
                }
                else
                {
                    return mySqlData;
                }
            }

        }

        private static int InsertSql(string[,] mySqlData)
        {
            SqlConnection connSql = SQLInfo.GetDBConnection();

            connSql.Open();

            SqlCommand cmdInsert = new SqlCommand("INSERT INTO dbo.[327_EOL_SERBIA] "
                + "([eolID], [order_number], [material_number], [serial_number], [runtime], [value_angle], [state_angle], [state_envelope], [state_label], [state_disenganging], [state_GETR], [datetime], [Copied_TS] )"
                + " VALUES (@eolID, @order_number, @material_number, @serial_number, @runtime, @value_angle, @state_angle, @state_envelope, @state_label, @state_disenganging, @state_GETR, @datetime, @Copied_TS)", connSql);
            int i = 0;


            try
            {
                for (i = 0; i <= mySqlData.GetUpperBound(0); i++)
                {
                    if (mySqlData[i, 0] == null) return i + 1;

                    cmdInsert.Parameters.AddWithValue("@eolID", Convert.ToInt64(mySqlData[i, 0]));
                    cmdInsert.Parameters.AddWithValue("@order_number", Convert.ToInt64(mySqlData[i, 1]));
                    cmdInsert.Parameters.AddWithValue("@material_number", Convert.ToInt32(mySqlData[i, 2]));
                    cmdInsert.Parameters.AddWithValue("@serial_number", mySqlData[i, 3]);
                    cmdInsert.Parameters.AddWithValue("@runtime", Convert.ToDouble(mySqlData[i, 4]));
                    cmdInsert.Parameters.AddWithValue("@value_angle", Convert.ToDouble(mySqlData[i, 5]));
                    cmdInsert.Parameters.AddWithValue("@state_angle", Convert.ToByte(mySqlData[i, 6]));
                    cmdInsert.Parameters.AddWithValue("@state_envelope", Convert.ToByte(mySqlData[i, 7]));
                    cmdInsert.Parameters.AddWithValue("@state_label", Convert.ToByte(mySqlData[i, 8]));
                    cmdInsert.Parameters.AddWithValue("@state_disenganging", Convert.ToByte(mySqlData[i, 9]));
                    cmdInsert.Parameters.AddWithValue("@state_GETR", Convert.ToByte(mySqlData[i, 10]));
                    cmdInsert.Parameters.AddWithValue("@datetime", Convert.ToDateTime(mySqlData[i, 11]));
                    cmdInsert.Parameters.AddWithValue("@Copied_TS", DateTime.UtcNow);
                    cmdInsert.ExecuteNonQuery();

                    cmdInsert.Parameters.Clear();
                }

                return i;
            }
            catch (Exception er)
            {
                log.createLog(eol + "Error  " + er.ToString());
                return i;
            }
            finally
            {
                cmdInsert.Dispose();
                connSql.Close();
                connSql.Dispose();
            }
        }

        private static void UpdateMySQL(string[,] mySqlData)
        {
            MySqlConnection connMySql = MySQLInfo.GetDBConnection();
            MySqlCommand cmdMySQL = connMySql.CreateCommand();

            string sqlUpdate = "UPDATE tbl_prod_check_getr SET Copy_TS_SQL ='" + DateTime.UtcNow.ToString("yyyy-MM-dd HH':'mm':'ss") + "', Copyed_SQL = 1 WHERE ID = @ID";

            cmdMySQL.Connection = connMySql;
            cmdMySQL.CommandText = sqlUpdate;
            connMySql.Open();

            int i;

            try
            {
                for (i = 0; i <= mySqlData.GetUpperBound(0); i++)
                {
                    cmdMySQL.Parameters.AddWithValue("@ID", Convert.ToInt64(mySqlData[i, 0]));
                    cmdMySQL.ExecuteNonQuery();

                    cmdMySQL.Parameters.Clear();
                }

                log.createLog(eol + "Success: " + (i) + " Rows updated in MySQL");
            }

            catch (Exception er)
            {
                log.createLog(eol + er.ToString());
            }

            finally
            {
                cmdMySQL.Dispose();
                connMySql.Close();
                connMySql.Dispose();
            }
        }

    }
}

Vielen Dank für die Hilfe

Gruß freakontour

16.827 Beiträge seit 2008
vor 4 Jahren

Lager Deine Logik ordentlich aus ( [Artikel] Drei-Schichten-Architektur ), sodass du diese zB als Konsolenanwendung oder eben als Service starten kannst.
Damit machst Du Dir den gesamten Entwicklungsprozess -und auch das Debugging - deutlich einfacher.

M
368 Beiträge seit 2006
vor 4 Jahren

In der Java-Welt gibt es für DB-Migration und Verfolgen von Änderungen Werkzeuge namens "Flyway" und "Liquibase". Vielleicht gibt es etwas Analoges für .NET (ausser der "zu-Fuss-Methode" )

Goalkicker.com // DNC Magazine for .NET Developers // .NET Blogs zum Folgen
Software is like cathedrals: first we build them, then we pray 😉

F
10.010 Beiträge seit 2004
vor 4 Jahren

Stoppe den Timer vor dem dataEx.StartExchange(); und starte ihn danach wieder.
So wie du es hast, kann er ggf schon wieder zuschlagen bevor du mit der Aufgabe fertig bist.

Ganz abgesehen davon, Arrays sind die komplett falsche Datenstruktur für so etwas.
Und mit SqlBulkCopy wird das deutlich performanter

F
freakontour Themenstarter:in
15 Beiträge seit 2015
vor 4 Jahren

Hallo Fzelle,

danke für die Infos.
Habe die Timerzeit erhöht und plötzlich klappt es.
Werde mir deinen Vorschlag anschauen und versuchen umzusetzen.

Gruß freakontour

F
freakontour Themenstarter:in
15 Beiträge seit 2015
vor 4 Jahren

Hallo,

ich versuche nun das BulkSQLCopy umzusetzten, jedoch wird immer die Anmeldung nicht durchgeführt. Im SQL-Server steht, dass das Passwort nicht mit der Anmeldung übereinstimmt. Jedoch kann ich mit "dem alten Weg" über den Connectionstring zugreifen.

In der Console wird die Verbindung als offen angezeigt.


        private static void CopySQLData(MySqlDataReader reader)
        {
            SqlConnection connSql = SQLInfo.GetDBConnection();
            connSql.Open();
            Console.WriteLine(connSql.State.ToString());
            Console.WriteLine(connSql.ConnectionString.ToString());
            SqlBulkCopy sbc = new SqlBulkCopy(connSql.ConnectionString);
            

                try
                {
                    sbc.DestinationTableName = "327_EOL_SERBIA";
                    sbc.SqlRowsCopied += new SqlRowsCopiedEventHandler(OnSqlRowsCopied);
                    sbc.BatchSize = 1000;
                    sbc.NotifyAfter = 1000;
                    sbc.ColumnMappings.Add("eolID", "ID");
                    //sbc.ColumnMappings.Add("order_number", "order_number");
                    //sbc.ColumnMappings.Add("serial_number","serial_number")
                    sbc.WriteToServer(reader);
                }
                catch (Exception er)
                {
                    log.createLog(eol + er.ToString());
                }
                finally
                {
                    
                    sbc.Close();
                    connSql.Close();
            }
           
        }
F
10.010 Beiträge seit 2004
vor 4 Jahren

Schon mal im Debugger geschaut was da als im Connectionstring steht?

Und warum nimmst du nicht die SqlConnection die du ohnehin schon benutzt?

F
freakontour Themenstarter:in
15 Beiträge seit 2015
vor 4 Jahren

Es ist genau die gleiche Connection wie vorher. Beim Insert-Befehl funktioniert es. Der Connection-String enthält alles bis auf das Passwort. Das Property _ConnectionString enthält die Verbindungsfolge mit Password.

Ich verstehe hier auch den Fehler nicht:
Connection string wird so aufgebaut:


        public static SqlConnection GetDBConnection(string host, int port, string database, string username, string password)
        {
            //Connection String to Database
            String connString = @"Data Source=" + host + ";Initial Catalog=" + database +
                ";User ID=" + username + ";password=" + password;

            SqlConnection conn = new SqlConnection(connString);

            return conn;
        }

EDIT:
Es wird vom ConnectionString das Passwort nicht an den BULK SQL übergeben. Hatte jemand schonmal dieses Problem?

EDIT 2:
Problem lag am ConnectionString. Habe hier nicht den Builder genommen und somit wurden das Passwort nicht mitübergeben.

F
10.010 Beiträge seit 2004
vor 4 Jahren

Du hast das falsch verstanden.
SqlBulkCopy kann die Connection benutzen die du sowieso schon ein paar Zeilen drüber aufgemacht hast.