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 Egy 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:
/*===============================================================================
File: Program.cs
Dátum: 2011.12.31
Leírás: demo kód, sql progress info
SQL Server verziók: 2008 és újabb
Szerző: Berke János - IamBerke.com
---------------------------------------------------------------------------------
(cc) 2011, IamBerke.com
Szabadon másolható, módosítható, bemutatható a kód, amenniyben nem kereskedelmi
célokat szolgál. A kód megjelenhet nyomtatott vagy elektronikus formában,
amennyiben a forrás megjelenítésre kerül, de a megjelnéshez a szerző
előzetes jóváhagyása is szükséges.
A KÓD ÉS AZ INFORMÁCIÓK MINDENFÉLE GARANCIA NÉLKÜL "AS-IS" ÁLLNAK RENDELKEZÉSRE,
A SZERZŐ SEMMIFÉLE - SEM KÖZVETLEN, SEM KÖZVETETT - FELELŐSSÉGET NEM VÁLLAL.
================================================================================*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
namespace SqlProgressSample
{
class Program
{
static void Main(string[] args)
{
string connectionString = @"Data Source=.\SQL2K8R2; Initial Catalog=tempdb; Integrated Security=SSPI";
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
connection.InfoMessage += new SqlInfoMessageEventHandler(SqlProgressEvent);
connection.FireInfoMessageEventOnUserErrors = true;
using (SqlCommand command = new SqlCommand())
{
command.Connection = connection;
command.CommandText = @"SET NOCOUNT ON;
CREATE TABLE #T
(
id int
);
DECLARE @i int = 0;
PRINT 'Starting insert';
WHILE @i < 7999999
BEGIN
INSERT INTO #T ([id]) VALUES (@i);
SET @i += 1;
IF (@i % 10000 = 0)
RAISERROR (N'%d rows inserted.', 10, 1, @i) WITH NOWAIT;
END
SET NOCOUNT OFF;";
command.CommandType = System.Data.CommandType.Text;
command.ExecuteNonQuery();
}
}
}
private static void SqlProgressEvent(object sender, SqlInfoMessageEventArgs e)
{
if (e.Errors.Count > 0)
{
Console.WriteLine(e.Errors[0].Message);
}
}
}
}
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:
USE tempdb;
GO
SET NOCOUNT ON;
CREATE TABLE #T
(
id int
);
DECLARE @i int = 0;
WHILE @i < 7999999
BEGIN
INSERT INTO #T ([id]) VALUES (@i);
SET @i += 1;
IF (@i % 10000 = 0)
RAISERROR (N'%d rows inserted.', 10, 1, @i) WITH NOWAIT;
END
SET 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.