lundi 16 novembre 2009

[SQL Server 2008]Login associé à dbo est vide


Lors de la restauration d’une base de données, si le login propriétaire de dbo n’existe pas sur le nouveau serveur, le login associé à dbo est vide.

Nous pouvons modifier le login associé à l'utilisateur dbo avec la commande:

'sp_changedbowner login'

Par exemple, si on souhaite définir sa en tant que dbo sur la base de données nommée TEST :

1. Aller dans SQL Server Management Studio


2. Sélectionner la base de données


3. Cliquer droit puis sélectionner Nouvelle Requête


4. Exécuter la commande sp_changedbowner sa

jeudi 30 juillet 2009

SQL Server 2000 Mettre à jour le contenu d’une colonne du type NTEXT

Ci-dessous le script que j’ai utilisé pour mettre à jour une colonne du type NTEXT.
Le but est de remplacer un texte dans cette colonne.


SET NOCOUNT ON


DECLARE @ptrval binary(16);
DECLARE @offset int;

DECLARE @Cle varchar;
DECLARE @TexteARemplacer varchar; --Texte à remplacer
DECLARE @LenTexteARemplacer int; --Longueur de la chaîne à remplacer
DECLARE @NouveauTexte varchar; --Nouveau texte

SET @Cle = 'cle';
SET @TexteARemplacer = 'Texte à remplacer';
SET @LenTexteARemplacer = LEN(@TexteARemplacer)
SET @NouveauTexte = 'Nouveau texte';

-- Récupérer le contenu de la colonne à mettre à jour
SELECT
@ptrval = TEXTPTR(TEST_COLONNE_LIBELLE)
FROM TEST_TABLE
WHERE
TEST_COLONNE_CLE = ' + @Cle + '

--Récupérer la première position du texte à remplacer dans le libellé
SELECT
@offset = PATINDEX('%'+@TexteARemplacer+'%', TEST_COLONNE_LIBELLE) - 1
FROM TEST_TABLE
WHERE
TEST_COLONNE_CLE = ' + @Cle + '

--Mettre à jour le libellé
WHILE @offset > -1
BEGIN
UPDATETEXT TEST_TABLE.COLONNE_LIBELLE @ptrval @offset @LenTexteARemplacer @NouveauTexte;
SELECT
@offset = PATINDEX('%'+@TexteARemplacer+'%', COLONNE_LIBELLE) - 1
FROM TABLE
WHERE
COLONNE_CLE = ' + @Cle +'
END


SET NOCOUNT OFF

mercredi 29 juillet 2009

IE8 Impossible à débugger un projet web depuis Visual Studio s'il y a déjà IE8 ouvert

IE8 possède une propriété Loosely-Coupled Internet Explorer (LCIE) qui lui permet de s'exécuter sur plusieurs processus actives.

Débugger de Visual Studio n'arrive pas à déterminer sur quel processeur il faut attacher le débuggeur.
Vous pouvez corriger ce problème en désactivant la propriété "process growth" de LCIE.

1. Ouvrir RegEdit
2. Aller sur HKEY_LOCALMACHINE -> SOFTWARE -> Microsoft -> Internet Explorer -> Main
3. Ajouter un dword nommé TabProcGrowth
4. Adjuster TabProcGrowth à 0
5. Redémarrer IE8
Ce problème n'apparaît plus sur Visual Studio 2008.

mardi 28 juillet 2009

Impossible de démarrer le débogage sur le serveur web

J'ai trouvé des explications très complètes pour le message d'erreur : Impossible de démarrer le débogage sur le serveur web lorsqu’on lance un projet web ASP.NET sur Visual Studio .NET.

http://msdn.microsoft.com/en-us/library/aa290100(VS.71).aspx

Pour information, c’est écrit en anglais mais facile à comprendre.

vendredi 10 juillet 2009

sp_help_revlogin Transférer les utilisateurs entre SQL Server 2000 et 2008

Lors d'un projet de migration de base de données SQL Server 2000 vers 2008, j'ai recherché une procédure permettant de transférer les utilisateurs.

J’ai retrouvé un script sur le site laboratoire-microsoft.com, une version de procédure sp_help_revlogin pour SQL server 2005. J’ai essayé de l’exécuter mais j’ai obtenu un message d’erreur suivant :

Serveur : Msg 195, Niveau 15, État 10, Procédure sp_help_revlogin, Ligne 53
'LOGINPROPERTY' n'est pas un nom de fonction reconnu.


J’ai donc continué ma recherche. C’est sur le site de support de Microsoft que j’ai retrouvé la solution.


USE master
GO

IF OBJECT_ID ('sp_hexadecimal') IS NOT NULL
DROP PROCEDURE sp_hexadecimal
GO

CREATE PROCEDURE sp_hexadecimal
@binvalue varbinary(256),
@hexvalue varchar(256) OUTPUT
AS
DECLARE @charvalue varchar(256)
DECLARE @i int
DECLARE @length int
DECLARE @hexstring char(16)
SELECT @charvalue = '0x'
SELECT @i = 1
SELECT @length = DATALENGTH (@binvalue)
SELECT @hexstring = '0123456789ABCDEF'
WHILE (@i <= @length)
BEGIN
DECLARE @tempint int
DECLARE @firstint int
DECLARE @secondint int
SELECT @tempint = CONVERT(int, SUBSTRING(@binvalue,@i,1))
SELECT @firstint = FLOOR(@tempint/16)
SELECT @secondint = @tempint - (@firstint*16)
SELECT @charvalue = @charvalue +
SUBSTRING(@hexstring, @firstint+1, 1) +
SUBSTRING(@hexstring, @secondint+1, 1)
SELECT @i = @i + 1
END

SELECT @hexvalue = @charvalue
GO

IF OBJECT_ID ('sp_help_revlogin') IS NOT NULL
DROP PROCEDURE sp_help_revlogin
GO

CREATE PROCEDURE sp_help_revlogin @login_name sysname = NULL AS
DECLARE @name sysname
DECLARE @xstatus int
DECLARE @binpwd varbinary (256)
DECLARE @txtpwd sysname
DECLARE @tmpstr varchar (256)
DECLARE @SID_varbinary varbinary(85)
DECLARE @SID_string varchar(256)

IF (@login_name IS NULL)
DECLARE login_curs CURSOR FOR
SELECT sid, name, xstatus, password FROM master..sysxlogins
WHERE srvid IS NULL AND name <> 'sa'
ELSE
DECLARE login_curs CURSOR FOR
SELECT sid, name, xstatus, password FROM master..sysxlogins
WHERE srvid IS NULL AND name = @login_name
OPEN login_curs
FETCH NEXT FROM login_curs INTO @SID_varbinary, @name, @xstatus, @binpwd
IF (@@fetch_status = -1)
BEGIN
PRINT 'No login(s) found.'
CLOSE login_curs
DEALLOCATE login_curs
RETURN -1
END
SET @tmpstr = '/* sp_help_revlogin script '
PRINT @tmpstr
SET @tmpstr = '** Generated '
+ CONVERT (varchar, GETDATE()) + ' on ' + @@SERVERNAME + ' */'
PRINT @tmpstr
PRINT ''
PRINT 'DECLARE @pwd sysname'
WHILE (@@fetch_status <> -1)
BEGIN
IF (@@fetch_status <> -2)
BEGIN
PRINT ''
SET @tmpstr = '-- Login: ' + @name
PRINT @tmpstr
IF (@xstatus & 4) = 4
BEGIN -- NT authenticated account/group
IF (@xstatus & 1) = 1
BEGIN -- NT login is denied access
SET @tmpstr = 'EXEC master..sp_denylogin ''' + @name + ''''
PRINT @tmpstr
END
ELSE BEGIN -- NT login has access
SET @tmpstr = 'EXEC master..sp_grantlogin ''' + @name + ''''
PRINT @tmpstr
END
END
ELSE BEGIN -- SQL Server authentication
IF (@binpwd IS NOT NULL)
BEGIN -- Non-null password
EXEC sp_hexadecimal @binpwd, @txtpwd OUT
IF (@xstatus & 2048) = 2048
SET @tmpstr = 'SET @pwd = CONVERT (varchar(256), ' + @txtpwd + ')'
ELSE
SET @tmpstr = 'SET @pwd = CONVERT (varbinary(256), ' + @txtpwd + ')'
PRINT @tmpstr
EXEC sp_hexadecimal @SID_varbinary,@SID_string OUT
SET @tmpstr = 'EXEC master..sp_addlogin ''' + @name
+ ''', @pwd, @sid = ' + @SID_string + ', @encryptopt = '
END
ELSE BEGIN
-- Null password
EXEC sp_hexadecimal @SID_varbinary,@SID_string OUT
SET @tmpstr = 'EXEC master..sp_addlogin ''' + @name
+ ''', NULL, @sid = ' + @SID_string + ', @encryptopt = '
END
IF (@xstatus & 2048) = 2048
-- login upgraded from 6.5
SET @tmpstr = @tmpstr + '''skip_encryption_old'''
ELSE
SET @tmpstr = @tmpstr + '''skip_encryption'''
PRINT @tmpstr
END
END
FETCH NEXT FROM login_curs INTO @SID_varbinary, @name, @xstatus, @binpwd
END
CLOSE login_curs
DEALLOCATE login_curs
RETURN 0
GO

Il s’agit de créer deux procédures stockées nommées sp_hexadecimal et sp_help_revlogin dans la base de données master.


Après avoir créé la procédure stockée sp_help_revlogin, je l’ai exécutée à partir de l'Analyseur de requêtes du serveur SQL Server 2000.
EXEC master.sp_help_revlogin;

La procédure stockée sp_help_revlogin produit des scripts de connexion qui créent des noms d'accès avec le SID et le mot de passe d'origine. J’ai fait copier-coller de la sortie, puis je l’ai exécutée dans l'Analyseur de requêtes du serveur SQL Server 2008.

jeudi 23 avril 2009

Validation de procédures stockées dans la base SQL Server

Dans un projet, j’ai travaillé avec des applications qui utilisent de nombreuses procédures stockées. Ceci donne la facilité qu’en cas de bug urgent, nous pouvons corriger la procédure concernée sans faire une livraison complète de l’application.

Un jour, on est amené à faire de nettoyage dans la base de données afin de supprimer des colonnes non utilisées. Il nous fallait un moyen de vérifier la validité des procédures stockées après la suppression des colonnes.

Pour cela j’ai fait une application Windows qui permet de valider les objets dans la base de données.
Plus loin, j’ai développé un outil qui permet de comparer l’état des bases de données. Dans mon cas, je l’utilise pour comparer la base de données de développement et celle de la production. Le comparateur de bases de données sera abordé prochainement.

Ci-dessous un extrait de code pour valider les objets de la base de données:

// Connexion à la base de données
SqlConnection conn = new SqlConnection("Data Source=" + pServer + ";Initial Catalog="+pDb+";User Id="+login+";Password="+password+";");
conn.Open();

/*Requête sur la table système sysobjects pour récupérer les objets de la base de données suivant le type d’objet (P pour procédure stockée, V pour vue,…)
OBJECTPROPERTY (id, propriété): Retourne les informations concernant les objets (id = id de l’objet)
OBJECTPROPERTY(id,'ExecIsQuotedIdentOn') : retourne la propriété de QUOTED_IDENTIFIER lors de création de l’objet
OBJECTPROPERTY(id, 'ExecIsAnsiNullsOn') : retourne la propriété d’AISI NULLS lors de création de l’objet

*/
string cmdText = "SELECT name, OBJECTPROPERTY(id,'ExecIsQuotedIdentOn') as ident_on, " +
" OBJECTPROPERTY(id,'ExecIsAnsiNullsOn') as ainsi_null ,USER_NAME(uid) as owner " +
" FROM sysobjects WHERE xtype= '" + objectType+"'";
SqlDataAdapter daTable1 = new SqlDataAdapter(cmdText,conn);
DataSet ds = new DataSet("Table");
daTable1.Fill(ds);

// Parcourir les objets
foreach(DataRow row in ds.Tables[0].Rows)
{
StringBuilder sbCmd = new StringBuilder();
StringBuilder sbCmdProc = new StringBuilder();
string objectName = row["name"].ToString();
string owner = row["owner"].ToString();
string ansi_null = Convert.ToBoolean(row["ainsi_null"])?"ON":"OFF";
string ident_on = Convert.ToBoolean(row["ident_on"])?"ON":"OFF";
SqlCommand cmd = new SqlCommand("",conn);
try
{
// sp_helptext : récupérer la definition d’objet
cmd = new SqlCommand("exec sp_helptext '" + owner + "." + objectName+"';",conn);
cmd.CommandType = CommandType.Text;
SqlDataReader drDef = cmd.ExecuteReader();

while(drDef.Read())
{
sbCmdProc.Append(drDef["text"].ToString());
}
drDef.Close();

// Ne pas exécuter la requête/ mode parse
sbCmd.Append("set noexec on;");


// Proriété ansi_null d’objet
sbCmd.Append("set ansi_nulls "+ ansi_null +";");


// Proriété quoted_identifier d’objet
sbCmd.Append("set quoted_identifier "+ ident_on+";");
cmd = new SqlCommand(sbCmd.ToString(),conn);
cmd.CommandType = CommandType.Text;
cmd.ExecuteNonQuery();

// Executer l’objet
cmd = new SqlCommand(sbCmdProc.ToString(),conn);
cmd.CommandType = CommandType.Text;
cmd.ExecuteNonQuery();
}
catch(Exception ex)
{
// Erreur dans l’exécution, l’objet n’est pas valide
// Ici, mettre un message d’erreur
}

finally
{
/*Mettre ainsi_null par défaut (ON) et quoted_identifier par défaut (OFF)
Et remettre en mode exécution
*/

sbCmd = new StringBuilder();
sbCmd.Append("set ansi_nulls ON;");
sbCmd.Append("set quoted_identifier OFF;");
sbCmd.Append("set parseonly off; set noexec off;");

cmd = new SqlCommand(sbCmd.ToString(),conn);
cmd.CommandType = CommandType.Text;
cmd.ExecuteNonQuery();
}
}
// Fermer la connexion de la base de données
conn.Close();

jeudi 16 avril 2009

Checkout from SVN and Rebuild Solution File from Command Line

I create a .bat file to checkout an application source from SVN and to rebuild solution file without opening Visual studio .NET.

rem ****Déclare path to Tortoise and Visual Studio .NET ***
set path=%path%;C:\Program Files\TortoiseSVN\bin;C:\Program Files\Microsoft Visual Studio .NET 2003\Common7\IDE\

rem ****Checkout application source from SVN****

rem ****/closeonend:1 Close automatically Tortoise Dialog Box if no error TortoiseProc.exe /command:checkout /path:"D:\MyProject" /url:"https://svn.toto.com/svnrepos/MyProject/trunk" /closeonend:1

rem ****Rebuild solution in debug mode - output to log file****
devenv.exe /rebuild Debug "D:\MyProject\MyProject.sln" /out "d:\logMyProject"

vendredi 27 mars 2009

Expérience avec AjaxControlToolKit

AjaxControlToolkit est un ensemble de contrôles servers issu d’un partenariat entre Microsoft et la communauté d’ASP.NET Ajax. Il contient des contrôles extendeurs ainsi que des contrôles web permettant de construire une application internet riche. Les contrôles extendeurs sont des contrôles auxquels nous pouvons ajouter des scripts clients (JavaScript,..) dans l’événement du contrôle. AjaxControlToolkit met également à disposition des contrôles d’animation permettant d’ajouter des effets visuels plus sophistiqués dans une page web.

AjaxControlToolkit est construit à partir ASP.NET 2.0 Ajax Extension. Le dernier release fonctionne sur le Framework .NET 3.5 SP1. La release contient le code source complet. Ceci permet d’utiliser les contrôles existants ainsi que la création de nouveaux contrôles.

Les avantages :
- Un ensemble des contrôles prêts à utiliser,
- Une intégration aisée dans l’environnement Visual Studio 2008
- Un développement rapide d’une interface web sophistiquée
- Compatible avec de nombreux navigateur web
- Un site web dédié contenant la documentation et des exemples

Avant d’utiliser….
Il faut savoir qu’il s’agit d’un nouveau produit. Ainsi par manque de maturité, il est nécessaire de faire la validation des maquettes. La connaissance de JavaScript est parfois utile afin d’adapter les contrôles aux besoins très spécifiques du projet.


Téléchargement du package d’AjaxControlToolkit
Le package complet (avec code source) peut être téléchargé à partir de l’adresse suivante :
http://ajaxcontroltoolkit.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=16488


Les contenus téléchargés :
* AjaxControlToolkit – Contient la source ainsi que les contrôles d’Ajax* SampleWebsite – Site web qui montre comment utiliser les contrôles
* ToolkitTests – Site web qui contient des tests automatisés pour tous les contrôles
* AjaxControlExtender – Installeur de Template pour créer un nouveau contrôle extendeur avec Visual Studio 2008 SP1.

Pour commencer avec Visual Studio .NET 2008
1. Créer un nouveau site web.
2. Cliquer droit sur la boîte à outil -> Ajouter un onglet
3. Cliquer droit sur le nouveau onglet, sélectionner « Choisir les éléments ».
4. Cliquer sur le bouton « parcourir »
5. Aller dans le répertoire d’AjaxControlToolkit téléchargé. Sélectionner la dll AjaxControlToolkit.dll dans le répertoire « SampleWebSite/bin ».
6. Cliquer sur OK pour fermer la boite de dialogue.
L’ensemble des nouveaux contrôles seront visibles sur la boite à outil.

Lorsque nous faisons un drag and drop d’un de ces contrôles dans le formulaire web, la directive Registrer sera ajouté en haut de formulaire.
Afin d’éviter d’avoir cette déclaration dans plusieurs pages, nous pouvons très bien l’insérer une fois pour toute dans le fichier web.config. Pour cela, il faut déclarer dans la section configuration/system.web/pages/controls :
Par défaut le tagPrefix est nommé cc1. Remplacer avec un libellé plus compréhensible.

Afin de réaliser d’enchaînement des formulaires de validation, un web contrôle wizard est utilisé dans un contrôle d’extension Ajax UpdatePanel. Le wizard est affiché en pop up modal en grisant le contenu principal. Cela empêche l’utilisateur d’interagir avec la page principale pendant qu’il remplisse le wizard. Pour réaliser cela, le contrôle AjaxControlToolkit ModalPopupExtender est utilisé.

Le contrôle UpdatePanel permet de ne mettre à jour ses contenus lors d’un aller retour serveur.
Le contrôle Wizard permet d’avoir une interface multi étapes avec les boutons suivant-précédent et la gestion des états intégrés.
Le contrôle ModalPopupExtender permet d’ouvrir un élément de page en tant que pop up modal.
L’ouverture se fera côté client. Lorsqu’il est nécessaire de faire un postback, il suffit d’ajouter la propriété OnClick sur les boutons d’ouverture/de fermeture de pop up.

Ci-dessous un extrait de la page aspx :

Pour aller plus loin : http://ajaxcontroltoolkit.com/

mercredi 18 mars 2009

Could not load type 'System.Web.UI.ScriptReferenceBase'

I am currently working on a web site project using AjaxControlToolKit with .NET3.5 SP1.
Today I deploy the web site into a test server Windows 2008.
I was surprised as I got this message on the browser:
Could not load type 'System.Web.UI.ScriptReferenceBase' from assembly 'System.Web.Extensions, Version=3.5.0.0,...


After workaround I found that .NET3.5 is installed on my machine but not on the server.
But with this tricky solution, I did not need to install .NET3.5 SP1 version on server nor recompile my web site with .NET 3.5.

Replace ajaxToolkit:ToolkitScriptManager to asp:ScriptManager in the aspx file.


mardi 3 mars 2009

Générer Excel en C#

GENERATION EXCEL VIA OBJET COM
La génération utilise directement l’objet Excel installé sur le poste.
Avantages :
- Emuler l’interface d’utilisateur Excel, avoir la main sur chaque cellule Excel pour affter une valeur, la formater,…
- Le fichier généré du type d’Excel binaire (plus sécurisant)
Incovenients :
- Nécessite que Excel soit installé
- Le temps de génération est long si le fichier est volumineux
Mise en oeuvre
Pour povoir piloter Excel, il faut ajouter la référence vers le library d’Excel.
Ajouter ensuite dans la ligne directive « Using » cette ligne :
using Excel = Microsoft.Office.Interop.Excel;
Les classes les plus importantes dans le modèle d’objet Excel sont:
1. Microsoft.Office.Interop.Excel.Application représente l’application Excel
2. Microsoft.Office.Interop.Excel.Workbook représente un classeur dans l’application
3. Microsoft.Office.Interop.Excel.Worksheet représente une feuille d’Excel
4. Microsoft.Office.Interop.Excel.Range représente une cellule, une ligne, une colonne, une sélection de cellules contenant un ou plusieurs blocs de cellules. Avant de pouvoir manipuler une zone dans Excel, vous devez la spécifier comme étant un objet Range.

Dans cet exemple nous allons générer deux feuilles d’Excel. La première feuille contient une liste des notes et la deuxième feuille contient une liste des couleurs. Vous allez voir comment instancier on objet Excel, remplir chaque cellule, faire un formatage sur une cellule ainsi que sur un ensemble des cellules et enfin sauvegarder le fichier.

// Saisir le nom de fichier Excel à enregistrer
this.sfdExcel.FileName = "notes.xls";
if(this.sfdExcel.ShowDialog() == DialogResult.OK)
{
object Missing = System.Reflection.Missing.Value;

Excel.Application xlsApp;
Excel.Workbook xlsClasseur;
Excel.Worksheet xlsFeuille;
Excel.Range xlsRange;

// Créer un document Excel
xlsApp = new Excel.Application();
// Ne pas tenir compte des alertes
xlsApp.DisplayAlerts = false;

try
{
// Ajout d'un classeur
xlsClasseur = xlsApp.Workbooks.Add(true);

#region Première feuille
xlsFeuille = (Excel.Worksheet)xlsClasseur.Worksheets[1];

// Remplir la cellule [1,1] avec un libellé et mettre la couleur de fond gris
xlsFeuille.Cells[1,1] = "Ne pas modifier les données dans des cellules de cette couleur";
xlsRange = xlsFeuille.get_Range(xlsFeuille.Cells[1,1],xlsFeuille.Cells[1,5]);
xlsRange.Interior.ColorIndex = 15;
xlsRange.Merge(Missing);

// Les entêtes des colonnes
xlsFeuille.Cells[2,1] = "Nom";
xlsFeuille.Cells[2,2] = "Prénom";
xlsFeuille.Cells[2,3] = "Note";

// Les notes
xlsFeuille.Cells[3,1] = "LAGRANGE";
xlsFeuille.Cells[3,2] = "BERNADETH";
xlsFeuille.Cells[3,3] = 12.13;

xlsFeuille.Cells[4,1] = "LAMBUPOULOS";
xlsFeuille.Cells[4,2] = "ERIC";
xlsFeuille.Cells[4,3] = 17.51;

// Mettre la largeur de colonne suivant la longueur de texte
xlsRange = xlsFeuille.get_Range("A3","C3");
xlsRange.EntireColumn.AutoFit();

// Formatter les notes avec un seul virgule derrière
xlsRange = xlsFeuille.get_Range(xlsFeuille.Cells[3,3],xlsFeuille.Cells[4,3]);
xlsRange.NumberFormat = "0.0";


// Mettre les textes au milieu
xlsRange = xlsFeuille.get_Range(xlsFeuille.Cells[2,1],xlsFeuille.Cells[4,3]);
xlsRange.HorizontalAlignment = Excel.XlHAlign.xlHAlignCenter;

// Mettre le border couleur noir
xlsRange = xlsFeuille.get_Range(xlsFeuille.Cells[2,1],xlsFeuille.Cells[4,3]);
xlsRange.Borders.ColorIndex = 1;

#endregion

#region Deuxième feuille
xlsFeuille = (Excel.Worksheet)xlsClasseur.Worksheets.Add(Missing,xlsFeuille,1,Missing);
// Liste des couleurs de fond
for(int i = 1; i <= 56; i++) { xlsFeuille.Cells[i, 1] = i; xlsRange = xlsFeuille.get_Range(xlsFeuille.Cells[i,2],xlsFeuille.Cells[i,2]); xlsRange.Interior.ColorIndex = i; } #endregion // Enregistrer

xlsApp.ActiveWorkbook.SaveAs(this.sfdExcel.FileName,
Missing, Missing, Missing, Missing, Missing, Excel.XlSaveAsAccessMode.xlNoChange,
Missing, Missing,
Missing, Missing, Missing);
……….
GENERATION EXCEL VIA XML
La génération d’Excel enregistre le fichier sous forme de feuille de calcul XML.
Avantages :-Il ne nécessite pas qu’Excel soit installé
-La génération est rapide même si la taille de fichier généré est volumineuse
Inconvénients :
-La taille de fichier généré peut être deux fois plus la taille de fichier Excel par défaut
-Le fichier est généré est un fichier XML qu’on peut ouvrir avec un logiciel de texte (moins sécurisant)
Mise en œuvre
Il existe un library permettent de générer Excel via XML facilement.

Ce library est téléchargeable à partir de :
http://www.carlosag.net/Tools/ExcelXmlWriter/

Il est gratuit et est écrit entièrement en C#.

vendredi 27 février 2009

Parameters sniffing SQL Server

Ceci est un retour d’expérience lorsque j’ai travaillé sur un projet utilisant SQL Server 2000.

Lorsqu’une procédure stockée est créé, le plan d’éxécution n’est pas encore généré mais ce dernier est crée lors du premier appel à la procédure après sa compilation

Ce plan d’éxécution est ensuite stocké en cache et sera réutilisé.

Si la procédure possède des paramètres, lors du premier appel, les paramètres donnés seront pris en compte pour la compilation et la création du plan d’éxécution. Le plan sera donc optimisé par rapport à ces paramètres. C’est ce qu’on appelle « parameters sniffing ». Ce plan ne sera probablement pas optimisé pour d’autre valeur de paramètre.

Dans la plupart des requêtes, ce mécanisme ne pose pas de problème.

Mais lorsque la requête est complexe et que les valeurs ne sont pas bien distribuées sur la colonne filtrée, le « parameters sniffing » ralentit considérablement la procedure stocké du fait de la mauvaise estimation.

Lorsqu’une procédure stockée s’éxécute beacuoup plus lentement qu’une requête à la volée, les deux solutions ci-dessous peuvent être considérées :

1. Recompiler la procédure avant chaque exécution avec le mot clé « with recompile »
Exemple :
create Proc procTest (@pTest int)
with recompile
as
select colTest from tbTest where colTest = @pTest;



2. Utiliser les variables locales
Exemple:
create Proc procTest (@pTest int)
as
declare @varTest int
set @varTest = @pTest
select colTest from tbTest where colTest = @varTest;

dimanche 1 février 2009

Personalized pop-up message dialog box

This is only to refresh memory.

The other day I tried to find how to personalize a pop up message in winforms application.

















In fact, I created a new form with a multiline textbox. In the code behind, I added a public method which accepts a string parameter.












In the parent form, I called this method with the personalized message as parameter.













No surprise, it is so simple :).