Archive pour août 2007

Stopper un script de déploiement avec DBPros

10 août 2007

Dans mon script de pré-déploiement, je souhaite arrêter le déploiement si une base de données n’existe pas.

Comme indiqué en entête de Script.PreDeployment.sql, je me décide à utiliser la syntaxe de SQLCMD (qui sera utilisé pour jouer mon script).

J’écris donc une commande de ce style :

IF NOT EXISTS (SELECT 1 FROM [sys].[databases] WHERE [name] = N'$(DatabaseName)')
   QUIT

Seulement, comme pour les variables, l’étape de parsing à la compilation d’un projet de base de données ne supporte pas le mot-clé QUIT (ni EXIT d’ailleurs). Donc impossible de sortir du script sur une condition.

Solution de contrournement : lever une erreur avec l’instruction RAISERROR et utiliser l’option -b avec SQLCMD pour stopper le script sur erreur

IF NOT EXISTS (SELECT 1 FROM [sys].[databases] WHERE [name] = N'$(DatabaseName)')
  RAISERROR(N'Database $(DatabaseName) does not exists, setup could not be execute.',0,1)

 

Gestion des variables dans Visual Studio Team Edition for Database Professionals SR1

6 août 2007

J’étais super content que la SR1 de TeamDB (ou DBPros alias Visual Studio Team Edition for Database Professional) sorte enfin des cartons. En effet, j’en avais besoin pour utiliser les variables au niveau projet. J’ai été un peu déçu de voir qu’on ne pouvait les utiliser que dans un contexte restreint.

Laissez moi vous décrire le besoin que j’avais dans mes scripts de pré et post déploiement. Je voulais appliquer des scripts conditionnels en fonction du mode de compilation (release ou debug). Ce que je voudrais ressemblerait à peu près à cela :

IF $(DEBUG) = 1
 Begin
 --test data for development environment
 INSERT INTO dbo.myTable VALUES('some data')
 End

Dans les propriétés du projet ça donne cela :

Mais $(DEBUG) utilisé comme ci-dessus génère une erreur au parsing pendant la compilation. En effet, selon l’outil, on ne peut pas utiliser une variable de cette façon alors que c’est conforme avec la syntaxe de l’outil SQLCMD qui est utilisé par DBPros pour jouer le script sur le serveur. Le parsing de la compilation n’accepte que l’utilisation dans une chaîne de caractères ou comme nom d’entité SQL Server (une table ou un serveur lié); ex : Select * From [$(TableName)].

J’utilise alors la solution de contournement suivante qui j’avoue n’est pas très élégante mais qui fonctionne :

Declare @debug as int
Select @debug = cast('$(DEBUG)' as int)
If  @debug = 1
  Begin
  --do my stuff
  print 'DEBUG MODE!!!'
  End

Si vous trouvez un méthode plus élégante, je suis preneur…

Mise en oeuvre de la recherche Full-Text dans SQL Server 2005

6 août 2007

Un petit article (de 20 pages quand même) sur le Full-Text de SQL Server. L’article complet est diponible ici :

Mise en oeuvre de la recherche Full-Text dans SQL Server 2005

Ici vous trouverez un script T-SQL d’exemple sur la base AdventureWorks : Script d’exemple.

Quelques morceaux choisis :

Création de l’index

[...]

Il faut indiquer au moteur d’indexation les éléments à indexer de la base de données. Les éléments que l’on indexe sont des colonnes. Pour cela on place un INDEX de type Full-Text sur la table en indiquant les champs, comme on ferait pour un index classique.

Dans l’exemple ci-dessous, on indexe la colonne Description dans la table ProductDescription :

CREATE FULLTEXT INDEX ON dbo.ProductDescription
([Description] LANGUAGE 0x40c)--French(France)
KEY INDEX PK_ProductDescription
ON NouveauCatalogue

Bien que la syntaxe soit ressemblante, les options diffèrent. Nous allons les détailler dans les chapitres suivants.

Il est possible de créer les index Full-Text sur des tables ou des vues mais ces dernières devront être indexées pour disposer d’une clé unique (cf. 3.2).

1.1 Langage

[...]([Description] LANGUAGE 0x40c [...]

Pour chaque colonne indexée, on peut (et je dirais même on doit) préciser la langue de cette colonne. Ce paramètre va permettre une indexation optimum car le moteur de recherche Full-Text va prendre en considération les spécificités culturelles du langage choisi. Ces spécificités impactent l’indexation elle-même et le requêtage du moteur de recherche.

Les modules sensibles à la langue choisie sont :

  • Le Word Breaker : ce module se charge du découpage des mots dans un texte. Il est évident que l’on ne traite pas le chinois traditionnel comme l’espagnol
  • Le Stemmer : ce module se charge de décliner les mots (pluriels, conjugaisons, etc.). Par exemple, ride va être décliné en rider, riding, rides, etc. en langue anglaise et fondre va être décliné en fondante, fondues, fond, etc. en français.
  • Les Noises : ce module se charge de nettoyer le texte à indexer dans mots « polluants ». Ainsi, des mots comme le ou la (the, of, etc. en anglais), les lettres isolées ne seront pas pris en compte par le moteur.

Vous pouvez voir la liste des langages supportés par l’indexation Full-Text dans la vue système sys.fulltext_languages.

1.2 Clé unique

[...]KEY INDEX PK_ProductDescription [...]

Pour créer un index Full-Text, on doit préciser une clé unique. Une clé primaire ou un index unique peuvent être utilisés. Cette clé unique permet à l’indexation de faire référence à l’enregistrement contenant le texte indexé.

La clé unique est nécessaire pour que le moteur de requêtage puisse retourner les enregistrements correspondants aux résultats de la recherche.

[...]

Change Tracking

[...]

1.1 Modes de mises à jour

Une des problématiques rencontrées avec la recherche Full-Text est la mise à jour des index. En effet, on peut le voir dans l’architecture décrite plus haut, l’index Full-Text n’est pas stocké dans SQL Server, ce qui a pour conséquence qu’il ne soit pas mis à jour automatiquement quand on modifie ou que l’on insert des enregistrements dans la table.

Le Full-Text propose plusieurs façons de mettre à jour les index :

  • Au fil de l’eau : c’est le CHANGE TRACKING
  • Reconstruction complète : FULL POPULATION
  • Incrémentale : INCREMENTAL POPULATION

Le premier choix peut sembler idéal car il permet d’avoir un index à jour en permanence. En effet, SQL Server se charge d’envoyer des requêtes de mise à jour au service d’indexation quand on modifie les champs indexés de la table. Mais ce mode comporte quelques contreparties, il entraine une consommation supplémentaire des ressources de votre serveur. Aussi, il peut y avoir une légère latence car l’envoi des requêtes se fait en asynchrone. Pour préserver les ressources, il est possible de ne répercuter les changements que manuellement par un job ou une requête.

Pour activer ou désactiver le change tracking, il suffit d’ajouter l’option suivante à la création de l’index :

WITH CHANGE_TRACKING { AUTO | MANUAL | OFF }

[...]

 

Je n’aime pas les FormView

3 août 2007

Même si je fais du web de façon intensive depuis plusieurs années, je n’ai jamais creusé les contrôles de databinding tout prêt de ASP.NET (ni 1.1, ni 2.0). Je peux même dire que je suis novice avec les GridView, FormView et autres DetailView.

Je suis confronté à ces contrôles depuis quelques mois maintenant dans le cadre de projets qui en tirent parti. Je dois dire que je commence à être séduit par ce mode de fonctionnement même si je reste accro aux “custom templated controls“.

Sauf que la semaine dernière j’ai découvert que la FormView a un fonctionnement que je n’aime pas du tout et qu’il est important de connaître pour bien maîtriser ce que l’on fait. Admettons que dans la FormView, vous placiez un LinkButton et un CustomValidator pour vérifier une condition. Le LinkButton a la propriété CausesValidation à true. Vous branchez l’événement click sur votre méthode et là, tout bascule, en déboguant, vous vous apercevez que la validation (votre méthode OnServerValidate) est appelée 2 fois.

La validation est garantie par la propriété CausesValidation du bouton comme on peut le voir ci-dessous dans la méthode RaisePostBackEvent du LinkButton via Reflector.

protected virtual void RaisePostBackEvent(string eventArgument)
{
    base.ValidateEvent(this.UniqueID, eventArgument);
    if (this.CausesValidation)
    {
        this.Page.Validate(this.ValidationGroup);
    }
    this.OnClick(EventArgs.Empty);
    this.OnCommand(new CommandEventArgs(this.CommandName, this.CommandArgument));
}

Mais qui appelle donc la validation une seconde fois ? On peut voir aussi dans cette méthode qu’un LinkButton lève l’événement Click mais aussi l’événement Command, même si on n’a pas précisé de CommandName. Le problème, c’est qu’un événement Command utilise le mécanisme de Bubbling (méthode OnBubbleEvent) et remonte dans la hierarchie de contrôle jusqu’à ce que quelqu’un l’intercepte. Et devinez qui le prend en charge ? La FormView !!

Sans vérifier si la FormView est à même de prendre en charge la commande (représentée par le paramètre CommandName), elle lance la validation comme on peut le voir dans le code de la méthode OnBubbleEvent().

if (causesValidation && (this.Page != null))
{
   this.Page.Validate(validationGroup);
}

Ce qui fait que si vous préférez utiliser l’événement Click, vous aurez 2 validations de la page (ou du ValidationGroup).

La solution :

  • utiliser l’événement Command de la FormView pour faire vos traitements dans les boutons se trouvant en son sein.
  • mettre la propriété CausesValidation à false et appeler manuellement Page.Validate() dans la méthode qui gère l’événement Click

Moralité : FormView stinks !

unable to build project output group ‘content files from WebApplication’

1 août 2007

Dans un projet de setup web, quand vous souhaitez copier les ‘Content Files’ des sorties d’un projet de type Web Application, si vous rencontrez un jour cette erreur, je vous propose la solution :

unable to build project output group 'content files from WebApplication'

Le problème vient du fait qu’un fichier du site Web n’est pas trouvé sur le disque (le petit icône avec un triangle jaune). La compilation du projet web ne génère aucun warning mais un projet de setup lève une erreur car lui a besoin du fichier manquant.

Plutôt que de vous arracher les cheveux, naviguez dans tous les répertoires du site dans le Solution Explorer (je sais ça peut être long) à la recherche du triangle jaune (ça ferait un bon titre pour un film) et supprimer cette référence.

Tips : cherchez en priorité dans le répertoire des images, c’est souvent là qu’il y a le plus de boxon fichiers.

 


Suivre

Get every new post delivered to your Inbox.

Joignez-vous à 203 followers