Ik ben bezig met een windows-applicatie dat een sql query op een database uitvoert, zoiets als "Query Analyzer". Ik heb ontdekt dat als een query wat langer duurt dan een paar seconden, de applicatie blokkeert. Dit werd ook bevestigd door google.
Mijn vele zoekacties op google gaven oplossingen met Threads of Backgroundworker. Ook werd de "Asynchronous Processing" (geïntroduceerd in ADO.NET 2.0) als oplossing aangeboden. Maar ook werd het juist afgeraden als het niet noodzakelijk is om meerdere query gelijktijdig uit te voeren.
Wat is nu de juiste manier om een sql query uit te voeren, zonder de applicatie te blokkeren?
Ik heb al wat pogingen gewaagd met Backgroundworker. Echter liep ik al tegen problemen aan dat ik de infomessage niet meer op de GUI kon laten zien. Ik gebruik de volgende code:
Als ik met deze code via VS2005 start, krijg ik een InvalidOperationException zodra er een Infomessage getoond moet worden, met de volgende beschrijving:
Doe ik nu iets verkeerd? Hoort het zo?
Is er een (andere) manier om de Infomessage (en eventueel StateChange, StatementCompleted, SqlException) i.s.m. de Backgroundworker naar de GUI-thread te krijgen?
Hoe kan ik netzoals in "Query Analyzer":
- een grid (of text) met resultaat tonen als er query-resultaat is?
- alleen berichten (o.a. Infomessage) tonen als er geen resultaat is (bv. bij een create van een storedprocedure)?
Mijn vele zoekacties op google gaven oplossingen met Threads of Backgroundworker. Ook werd de "Asynchronous Processing" (geïntroduceerd in ADO.NET 2.0) als oplossing aangeboden. Maar ook werd het juist afgeraden als het niet noodzakelijk is om meerdere query gelijktijdig uit te voeren.
Wat is nu de juiste manier om een sql query uit te voeren, zonder de applicatie te blokkeren?
Ik heb al wat pogingen gewaagd met Backgroundworker. Echter liep ik al tegen problemen aan dat ik de infomessage niet meer op de GUI kon laten zien. Ik gebruik de volgende code:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
| private void Button_Click(object sender, EventArgs e) { this.Cursor = Cursors.WaitCursor; // "ConnectionString()" bevat uiteraard de juiste ConnectionString, "this.QueryBox.Text" bevat de Query backgroundWorker1.RunWorkerAsync(new object[] { ConnectionString(), this.QueryBox.Text }); } private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { object[] args = e.Argument as object[]; string connection = args[0].ToString(); string query = args[1].ToString(); SqlConnection conn = new SqlConnection(connection); SqlCommand comm = new SqlCommand(query, conn); try { conn.Open(); comm.CommandType = CommandType.Text; conn.InfoMessage += new SqlInfoMessageEventHandler(Query_InfoMessage); conn.FireInfoMessageEventOnUserErrors = true; int result = comm.ExecuteNonQuery(); } catch (SqlException ex) { MessageBox.Show(ex.Message); } finally { conn.Close(); } } private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { this.Cursor = Cursors.Default; } void Query_InfoMessage(object sender, SqlInfoMessageEventArgs e) { for (int i = 0; i < e.Errors.Count; i++) { this.textBox1.AppendText(e.Errors[i].Message); this.textBox1.AppendText(Environment.NewLine); } } |
Als ik met deze code via VS2005 start, krijg ik een InvalidOperationException zodra er een Infomessage getoond moet worden, met de volgende beschrijving:
Als ik nu buiten VS2005, dus rechtstreeks de exe opstart en hetzelfde doe, gaat alles goed, query wordt uitgevoerd, Infomessage wordt getoond.Het is niet toegestaan een bewerking uit te voeren via verschillende threads: er werd vanaf een andere thread toegang gekregen tot het besturingselement textBox1 dan de thread waarop het element is gemaakt.
Doe ik nu iets verkeerd? Hoort het zo?
Is er een (andere) manier om de Infomessage (en eventueel StateChange, StatementCompleted, SqlException) i.s.m. de Backgroundworker naar de GUI-thread te krijgen?
Hoe kan ik netzoals in "Query Analyzer":
- een grid (of text) met resultaat tonen als er query-resultaat is?
- alleen berichten (o.a. Infomessage) tonen als er geen resultaat is (bv. bij een create van een storedprocedure)?