Hogyan írjunk ki állapotinformációt hosszan tartó adatbázis műveletnél.
Az üzleti felhasználók nem igazán szeretnek várakozni egy-egy lekérdezésünk eredményére, türelmetlenek. Egy aprócska trükkel, még az 1-2 percig tartó lekérdezésünket is “szeretni” fogják SmileEgy egyszerű példával szeretném ezt megmutatni: képzeljük el azt az esetet, amikor egy táblába 8M sort kell betölteni és szeretnénk látni, hogy éppen hol tart a betöltés.
Ehhez egy konzol alkalmazást készítettem:
1/*===============================================================================
2 File: Program.cs
3 Dátum: 2011.12.31
4 Leírás: demo kód, sql progress info
5 SQL Server verziók: 2008 és újabb
6 Szerző: Berke János - IamBerke.com
7---------------------------------------------------------------------------------
8 (cc) 2011, IamBerke.com
9
10 Szabadon másolható, módosítható, bemutatható a kód, amenniyben nem kereskedelmi
11 célokat szolgál. A kód megjelenhet nyomtatott vagy elektronikus formában,
12 amennyiben a forrás megjelenítésre kerül, de a megjelnéshez a szerző
13 előzetes jóváhagyása is szükséges.
14
15 A KÓD ÉS AZ INFORMÁCIÓK MINDENFÉLE GARANCIA NÉLKÜL "AS-IS" ÁLLNAK RENDELKEZÉSRE,
16 A SZERZŐ SEMMIFÉLE - SEM KÖZVETLEN, SEM KÖZVETETT - FELELŐSSÉGET NEM VÁLLAL.
17================================================================================*/
18
19using System;
20using System.Collections.Generic;
21using System.Linq;
22using System.Text;
23using System.Data.SqlClient;
24
25namespace SqlProgressSample
26{
27 class Program
28 {
29 static void Main(string[] args)
30 {
31 string connectionString = @"Data Source=.\SQL2K8R2; Initial Catalog=tempdb; Integrated Security=SSPI";
32
33 using (SqlConnection connection = new SqlConnection(connectionString))
34 {
35 connection.Open();
36 connection.InfoMessage += new SqlInfoMessageEventHandler(SqlProgressEvent);
37 connection.FireInfoMessageEventOnUserErrors = true;
38
39 using (SqlCommand command = new SqlCommand())
40 {
41 command.Connection = connection;
42 command.CommandText = @"SET NOCOUNT ON;
43
44 CREATE TABLE #T
45 (
46 id int
47 );
48
49 DECLARE @i int = 0;
50 PRINT 'Starting insert';
51 WHILE @i < 7999999
52 BEGIN
53 INSERT INTO #T ([id]) VALUES (@i);
54 SET @i += 1;
55
56 IF (@i % 10000 = 0)
57 RAISERROR (N'%d rows inserted.', 10, 1, @i) WITH NOWAIT;
58 END
59 SET NOCOUNT OFF;";
60 command.CommandType = System.Data.CommandType.Text;
61 command.ExecuteNonQuery();
62 }
63
64 }
65 }
66
67 private static void SqlProgressEvent(object sender, SqlInfoMessageEventArgs e)
68 {
69 if (e.Errors.Count > 0)
70 {
71 Console.WriteLine(e.Errors[0].Message);
72 }
73 }
74
75
76 }
77}
2 fontos dolgot kell kiemelni a fenti kódból:
- SqlInfoMessageEventHandler delegate: erre van szükségünk, hogy az info üzeneteket elérjük. Ezek a PRINT vagy a RAISERROR megfelelő hívásaival hozható létre.
- PRINT vagy RAISERROR az SQL kódban.
Az alábbi SQL kód volt a konzol alkalmazásban is használva, ami minden 10000 beszúrás után kiírta, hogy éppen mennyinél jár:
1USE tempdb;
2GO
3
4SET NOCOUNT ON;
5
6CREATE TABLE #T
7(
8 id int
9);
10
11DECLARE @i int = 0;
12
13WHILE @i < 7999999
14 BEGIN
15 INSERT INTO #T ([id]) VALUES (@i);
16 SET @i += 1;
17
18 IF (@i % 10000 = 0)
19 RAISERROR (N'%d rows inserted.', 10, 1, @i) WITH NOWAIT;
20 END
21SET NOCOUNT OFF;
A RAISERROR 10-es severity-vel került meghívásra, illetve a WITH NOWAIT opcióval. Ez utóbbi arra szolgál, hogy a kliens fel az info üzeneteket azonnal elküldi, nem várja meg a lekérdezés lefutását.
Ahhoz, hogy ez minden esteben működjön a C# kódban az SqlConnection FireInfoMessageEventOnUserErrors tulajdonságát TRUE értékre kell állítani.