myCSharp.de - DIE C# und .NET Community
Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 
 | Suche | FAQ

» Hauptmenü
myCSharp.de
» Startseite
» Forum
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Suche
» Regeln
» Wie poste ich richtig?
» Forum-FAQ

Mitglieder
» Liste / Suche
» Wer ist wo online?

Ressourcen
» openbook: Visual C#
» openbook: OO
» Microsoft Docs

Team
» Kontakt
» Übersicht
» Wir über uns

» myCSharp.de Diskussionsforum
Du befindest Dich hier: Community-Index » Diskussionsforum » Entwicklung » GUI: Windows-Forms » [gelöst] Datenabruf aus DB soll in Thread ausgelagert werden
Letzter Beitrag | Erster ungelesener Beitrag Druckvorschau | Thema zu Favoriten hinzufügen

Antwort erstellen
Zum Ende der Seite springen  

[gelöst] Datenabruf aus DB soll in Thread ausgelagert werden

 
Autor
Beitrag « Vorheriges Thema | Nächstes Thema »
Riv3r Riv3r ist männlich
myCSharp.de-Mitglied

Dabei seit: 13.06.2007
Beiträge: 206
Entwicklungsumgebung: Visual Studio 2008 Prof


Riv3r ist offline

[gelöst] Datenabruf aus DB soll in Thread ausgelagert werden

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Guten Morgen,

in einem Programm werden teilweise sehr lange Methoden aufgerufen in denen viele Selects auf eine Datenbank abgesetzt werden.

Da der Anwender sehen soll, dass der Rechner noch arbeitet habe ich mir eine Control erstellt ( Animiertes GIF ruckelt) dass angezeigt werden soll sobald der User den Vorgang gestartet hat.

Mein Problem ist jetzt dass sich das gif nicht mehr dreht sobald die Methode aufgerufen wird (Grund - glaube ich:  [FAQ] Warum blockiert mein GUI?).

Jetzt habe ich mir überlegt die DB Zugriffe in Threads zu packen ODER in das "WaitControl" über einen Thread laufen zu lassen.
Weiß nicht was besser ist. Habe aber keins von beiden hinbekommen.

Datenbank:

C#-Code:
internal static void CallMSSQLProcedure(string procedureName, ProcedureParameter[] paraArray)
        {
               SqlCommand cmd = new SqlCommand(procedureName, GlobalConnectMSSQL as SqlConnection);
                cmd.CommandType = CommandType.StoredProcedure;

                foreach (ProcedureParameter param in paraArray)
                {
                    cmd.Parameters.AddWithValue(param.Name, param.Value);
                }

                cmd.ExecuteNonQuery();

           }

Wo sollte ich jetzt da den Thread starten/erzeugen?

Das waitControl wird beim Klick auf einen Button einfach nur sichtbar geschalten:

C#-Code:
//Buttonklick ruft ErstelleAngebot() auf.

private void ErstelleAngebot()
{
      waitControl.Visible = true;
      //Hier passieren die aufwendigen Dinge...
      waitControl.Visible = false;
}

Ich weiß nicht wie ich weiterkommen soll...

Die obigen FAQs habe ich gelesen sowie  Controls von Thread aktualisieren lassen (Invoke-/TreeView-Beispiel) und  [FAQ] Controls von Thread aktualisieren lassen (Control.Invoke)

Danke schonmal.

Gruß,
Max

Dieser Beitrag wurde 4 mal editiert, zum letzten Mal von Riv3r am 30.11.2007 10:30.

28.11.2007 07:38 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
herbivore
myCSharp.de-Poweruser/ Experte

avatar-2627.gif


Dabei seit: 11.01.2005
Beiträge: 49.483
Entwicklungsumgebung: csc/nmake (nothing is faster)
Herkunft: Berlin


herbivore ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo Riv3r,

Zitat:
ODER in das "WaitControl" über einen Thread laufen zu lassen.

lass unbedingt die Finger davon! Alle GUI-Elemente gehören in einen GUI-Thread. Das steht aber auch in der FAQ. :-)

Zitat:
Wo sollte ich jetzt da den Thread starten/erzeugen?

An der Stelle, wo die langlaufende Aktion ausgeführt (genauer gesagt: angestoßen) werden soll.

herbivore
28.11.2007 07:48 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Riv3r Riv3r ist männlich
myCSharp.de-Mitglied

Dabei seit: 13.06.2007
Beiträge: 206
Entwicklungsumgebung: Visual Studio 2008 Prof

Themenstarter Thema begonnen von Riv3r

Riv3r ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo herbivore,

danke für deine (wie immer) schnelle Antwort!

Zitat:
An der Stelle, wo die langlaufende Aktion ausgeführt (genauer gesagt: angestoßen) werden soll.

Wenn ich jedes Mal wenn eine Procedure aufgerufen wird einen eigenen Thread aumachen würde hätte ich das überall in meinen Programmen. Oder ist das nicht so sinnvoll das in der Datenschicht zu machen?

Wie soll ich den Thread starten?

C#-Code:
internal static void CallMSSQLProcedure(string procedureName, ProcedureParameter[] paraArray)
        {
               SqlCommand cmd = new SqlCommand(procedureName, GlobalConnectMSSQL as SqlConnection);
                cmd.CommandType = CommandType.StoredProcedure;

                foreach (ProcedureParameter param in paraArray)
                {
                    cmd.Parameters.AddWithValue(param.Name, param.Value);
                }
                Thread t = new Thread(new ThreadStart(ExecuteNonQuery???????);
                t.Start();

                 //cmd.ExecuteNonQuery();

           }

Oder lieber in der Präsentationsschicht?

C#-Code:
buttonklick
{
      waitControl.Visible = true;
      Thread t = new Thread(new ThreadStart(erstelleAngebot));
      waitControl.Visible = false;
}

erstelleAngebot()
{
      //do
}

Gruß,
Max

Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von Riv3r am 28.11.2007 08:04.

28.11.2007 08:03 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
herbivore
myCSharp.de-Poweruser/ Experte

avatar-2627.gif


Dabei seit: 11.01.2005
Beiträge: 49.483
Entwicklungsumgebung: csc/nmake (nothing is faster)
Herkunft: Berlin


herbivore ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo Riv3r,

Zitat:
Wenn ich jedes Mal wenn eine Procedure aufgerufen wird einen eigenen Thread aumachen würde hätte ich das überall in meinen Programmen. Oder ist das nicht so sinnvoll das in der Datenschicht zu machen?

Unabhängig davon, ob die Datenbankoperationen schnell sind oder lange brauchen, also unabhängig davon, ob man Threads braucht, damit das GUI nicht blockiert, sollte Aufgrund der Trennung von GUI, Modell und Datenschicht, im GUI keine Datenbankoperationen durchgeführt werden. Das GUI sollte von SQL nichts wissen und nichts sehen. Alle datenbank(spezifischen) Dinge gehören in Datenschicht. Es sollte möglich sein, die Datenbank auszutauschen (z.B. eine SQL-Datenbank durch eine Objekt(daten)bank zu ersetzen), ohne dass Modell und GUI etwas davon merken.

Wenn die Datenbankoperationen lange laufen (können), dann werden Threads aufgrund der Erfordernisse des GUIs nötig. Deshalb gehört das Threading in das GUI und nicht in die Datenschicht.

Wenn du häufig langlaufende Operationen startest, dann kannst du auch einen Thread dafür verwenden, statt jedes mal einen neuen zu starten. Der Thread könnte z.B. seine Arbeitsaufträge über eine (synchronisierte) Queue bekommen.

Trotzdem ändert sich nichts daran, dass die langlaufende Aktion an der Stelle bzw. an den Stellen angestoßen werden muss, wo dies nötig ist, also i.d.R. als Reaktion auf Benutzeraktionen.

herbivore
28.11.2007 08:24 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Riv3r Riv3r ist männlich
myCSharp.de-Mitglied

Dabei seit: 13.06.2007
Beiträge: 206
Entwicklungsumgebung: Visual Studio 2008 Prof

Themenstarter Thema begonnen von Riv3r

Riv3r ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Halle herbivore,

Zitat:
sollte Aufgrund der Trennung von GUI, Modell und Datenschicht, im GUI keine Datenbankoperationen durchgeführt werden.

Die Trennung besteht und im GUI werden auch keine SQLs usw. ausgeführt sondern nur Methoden aus der Modellschicht aufgerufen die wiederum auf die Datenschicht Zugriff haben.

Zitat:
Deshalb gehört das Threading in das GUI und nicht in die Datenschicht

Threads ins GUI, alles klar!

Hab das jetzt auch versucht:

C#-Code:
buttonklick
{
     waitControl.Visible = true;
     Thread t = new Thread(new ThreadStart(erstelleAngebot));
     t.Start();
     waitControl.Visible = false;
}

erstelleAngebot()
{
//do
            DataTable table = new DataTable();
            DataTable tableSummen = new DataTable();

            IList<string> error = IMOS_to_FAS.CreateIMOSAngebot(_currentJobId, auftragsInfos, Convert.ToInt16(tsCheckBoxInclAbteilungspos.Checked), Convert.ToInt16(tsCheckBoxInclZwischensummen.Checked), table);
            if (error.Count > 0)
            {
                //IMOS_to_FAS.ClearAngebot(auftragsInfos.ProjektName, auftragsInfos.AuftragsName);
                TSErrorLog errorLog = new TSErrorLog("Fehlerhinweis", "Bitte beheben Sie die folgenden Fehler", error);
                errorLog.ShowDialog();
            }
            bsAngebot.DataSource = table;
            if (!tsGridAngebot.IsFormatted)
            {
                tsGridAngebot.LayoutGrid("");
            }

            IMOS_to_FAS.ReadAngebotsAbteilungsSummen(auftragsInfos, tableSummen);
            tsGridAbteilungen.DataSource = tableSummen;
}

jetzt läuft er aber bei der BindingSource bsAngebot auf einen Fehler (Unzulässiger threadübergreifender Vorgang...).

Gruß,
Max
28.11.2007 09:21 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
herbivore
myCSharp.de-Poweruser/ Experte

avatar-2627.gif


Dabei seit: 11.01.2005
Beiträge: 49.483
Entwicklungsumgebung: csc/nmake (nothing is faster)
Herkunft: Berlin


herbivore ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo Riv3r,

du darfst aus dem Thread nicht direkt auf die Controls und auch nicht auf gebundene Daten zugreifen, siehe  [FAQ] Controls von Thread aktualisieren lassen (Control.Invoke)

herbivore
28.11.2007 09:23 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Riv3r Riv3r ist männlich
myCSharp.de-Mitglied

Dabei seit: 13.06.2007
Beiträge: 206
Entwicklungsumgebung: Visual Studio 2008 Prof

Themenstarter Thema begonnen von Riv3r

Riv3r ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Habs jetzt noch n bischen versucht aber bekomms irgendwie nicht hin.

Ich habe auch deinen Artikel gelesen und weiß trotzdem nicht wie ich das machen soll.
Den Teil

C#-Code:
bsAngebot.DataSource = table;
            if (!tsGridAngebot.IsFormatted)
            {
                tsGridAngebot.LayoutGrid("");
            }

            IMOS_to_FAS.ReadAngebotsAbteilungsSummen(auftragsInfos, tableSummen);
            tsGridAbteilungen.DataSource = tableSummen;

muss ich irgendwie wegbekommen oder?

Hilfe wäre nett...

Gruß,
Max
28.11.2007 12:37 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
herbivore
myCSharp.de-Poweruser/ Experte

avatar-2627.gif


Dabei seit: 11.01.2005
Beiträge: 49.483
Entwicklungsumgebung: csc/nmake (nothing is faster)
Herkunft: Berlin


herbivore ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo Riv3r,

Zitat:
Den Teil ... muss ich irgendwie wegbekommen oder?

Wenn ReadAngebotsAbteilungsSummen keine langlaufende Aktion ist, pack den Teil in eine Methode und rufe diese per Control.Invoke auf.

Wenn ReadAngebotsAbteilungsSummen eine langlaufende Aktion ist, pack den Teil vor ReadAngebotsAbteilungsSummen in einem Methode und rufe diese per Control.Invoke auf und pack den Teil nach ReadAngebotsAbteilungsSummen in einem Methode und rufe diese per Control.Invoke auf.

herbivore
28.11.2007 13:27 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Riv3r Riv3r ist männlich
myCSharp.de-Mitglied

Dabei seit: 13.06.2007
Beiträge: 206
Entwicklungsumgebung: Visual Studio 2008 Prof

Themenstarter Thema begonnen von Riv3r

Riv3r ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo herbivore,

Habe das jetzt noch ein wenig versucht und siehe da es geht Augenzwinkern - fast...

C#-Code:
private void ErstelleAngebot()
        {
            tableAngebot = new DataTable();
            tableAbteilungsSummen = new DataTable();
            IList<string> error = IMOS_to_FAS.CreateIMOSAngebot(_currentJobId, auftragsInfos, Convert.ToInt16(tsCheckBoxInclAbteilungspos.Checked), Convert.ToInt16(tsCheckBoxInclZwischensummen.Checked), tableAngebot);
            if (error.Count > 0)
            {
                TSErrorLog errorLog = new TSErrorLog("Fehlerhinweis", "Bitte beheben Sie die folgenden Fehler", error);
                errorLog.ShowDialog();
            }
            this.Invoke(new MethodInvoker(ZeigeAngebot));
        }

buttonklick
{
         waitControl.Visible = true;
         waitControl.Refresh();
         Thread thread = new Thread(new ThreadStart(ErstelleAngebot));
         thread.Start();
         waitControl.Visible = false;
}

In ZeigeAngebot() ist der ander Code:

C#-Code:
bsAngebot.DataSource = table;
            if (!tsGridAngebot.IsFormatted)
            {
                tsGridAngebot.LayoutGrid("");
            }

            IMOS_to_FAS.ReadAngebotsAbteilungsSummen(auftragsInfos, tableSummen);
            tsGridAbteilungen.DataSource = tableSummen;

So jetzt 1: Läuft der ja nachdem er den Thread gestartet hat einfach weiter, d.h. man sieht das waitControl garnicht. Kann ich das Control so lange sichtbar halten wie der Thread aktiv ist?

2: Wird das Form errorLog nicht angezeigt.

Gruß,
Max
28.11.2007 16:00 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
herbivore
myCSharp.de-Poweruser/ Experte

avatar-2627.gif


Dabei seit: 11.01.2005
Beiträge: 49.483
Entwicklungsumgebung: csc/nmake (nothing is faster)
Herkunft: Berlin


herbivore ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo Riv3r,

im Thread solltest du keine GUI-Elemente verwenden, also auch nicht ShowDialog. Einfach gar nichts GUI-bezogenes außer Invoke. Alles GUI-bezogene gehört alles in den GUI-Thread. Wenn du das einhältst, sollte sowohl 1. als auch 2. funktionieren.

herbivore
28.11.2007 17:05 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Riv3r Riv3r ist männlich
myCSharp.de-Mitglied

Dabei seit: 13.06.2007
Beiträge: 206
Entwicklungsumgebung: Visual Studio 2008 Prof

Themenstarter Thema begonnen von Riv3r

Riv3r ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Halle herbivore,

Aber wo soll ich dass den dann hinpacken?
Ich brauche doch die IList mit den errors...

Hast du zu Problem 1 auch eine Lösung?

Gruß,
Max

Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von Riv3r am 28.11.2007 20:22.

28.11.2007 20:22 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
herbivore
myCSharp.de-Poweruser/ Experte

avatar-2627.gif


Dabei seit: 11.01.2005
Beiträge: 49.483
Entwicklungsumgebung: csc/nmake (nothing is faster)
Herkunft: Berlin


herbivore ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo Riv3r,

Zitat:
Aber wo soll ich dass den dann hinpacken?

Alles GUI-bezogene gehört in den GUI-Thread. Alles langlaufende in den (extra) Worker-Thread. Ganz einfach also.

Zitat:
Ich brauche doch die IList mit den errors...

Du kannst sowohl beim Starten eines Thread (GUI-Thread ==> Worker-Thread) als auch bei Control.Invoke (Worker-Thread ==> Gui-Thread) Parameter übergeben.

Zitat:
Hast du zu Problem 1 auch eine Lösung?

Ich bin der Meinung, dass sich beide Probleme lösen, wenn du die Aufgaben richtig auf die Threads verteilt hast.

herbivore
28.11.2007 20:29 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Riv3r Riv3r ist männlich
myCSharp.de-Mitglied

Dabei seit: 13.06.2007
Beiträge: 206
Entwicklungsumgebung: Visual Studio 2008 Prof

Themenstarter Thema begonnen von Riv3r

Riv3r ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo herbivore,

dank deines Tipps

Zitat:
Du kannst sowohl beim Starten eines Thread (GUI-Thread ==> Worker-Thread) als auch bei Control.Invoke (Worker-Thread ==> Gui-Thread) Parameter übergeben.

funktioniert jetzt alles so wie ich mir das vorgestellt habe Augenzwinkern


Gruß,
Max
29.11.2007 10:07 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Riv3r Riv3r ist männlich
myCSharp.de-Mitglied

Dabei seit: 13.06.2007
Beiträge: 206
Entwicklungsumgebung: Visual Studio 2008 Prof

Themenstarter Thema begonnen von Riv3r

Riv3r ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Ich habe noch eine kleine Frage:

Wenn ich die Methoden dann debuge läuft der Thread (worker) irgendwie auf einen Timeout oder so...

Fehlermeldung kommt keine er geht nur aus dem Debugmodus raus und hängt sich auf.

MfG
Max


EDIT:

OK liegt nicht an irgendeinem Timeout oder so - hab ne MessageBox ausgeben wollen, da hat er sich aufgehängt. Komisch aber dass ich keinen Fehler bekommen habe.

Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von Riv3r am 30.11.2007 10:34.

30.11.2007 10:26 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Baumstruktur | Brettstruktur       | Top 
myCSharp.de | Forum Der Startbeitrag ist älter als 13 Jahre.
Der letzte Beitrag ist älter als 13 Jahre.
Antwort erstellen


© Copyright 2003-2021 myCSharp.de-Team | Impressum | Datenschutz | Alle Rechte vorbehalten. | Dieses Portal verwendet zum korrekten Betrieb Cookies. 18.01.2021 18:55