Friday, July 29, 2005

Au détour d'une rencontre avec un guru du SQL, j'ai pu admirer le code suivant, permettant d'effacer tous le doublon d'une table. Imaginons une table (aTable) avec une seule colonne (aNumber), aucune clé, mais avec plusieurs lignes contenant la même valeur :


1
1
2
1
3
3
3
1
2
1


Le but est du supprimer tous les doublons, ceci en une seule requête. Vous avez la réponse ?


Voici le code SQL :


set rowcount 1

select 1
while @@rowcount > 0
delete test
where 1 < (select count(*) from test t2 where test.id = t2.id)

set rowcount 0


 


 


Some couple of weeks ago, I had the opportunity to meet SQL guru, and I have seen a very nice SQL code, deleting duplicates rows in a table. Let's imagine a table (aTable) with only one field (aNumber), without any key but multiple rows with the same value :


1
1
2
1
3
3
3
1
2
1


The goal is to delete duplicate values in only one SQL request. You have the answed ?


Here is the code :


set rowcount 1

select 1
while @@rowcount > 0
delete test
where 1 < (select count(*) from test t2 where test.id = t2.id)

set rowcount 0

Monday, July 11, 2005

A voir, BizTalk rencontre passablement de problèmes pour gérer les fichiers dont le volume est important. Pourtant, malgré les efforts entrepris pour ré architecturer l’application, il est parfois impossible de s’affranchir de ses OutOfMemoryException. Dans le cas du projet actuel, le problème ne se passe que lorsque BizTalk doit traiter plus d’un fichier en même temps. J’ai donc décidé, provisoirement, de ne soumettre à BizTalk qu’un seul fichier à la fois, et attendre qu’il en ait terminé le traitement avant d’en soumettre le suivant. Or, il me semble qu’il n’est pas possible d’être averti lorsqu’une orchestration se termine, dans le framework .NET.


La méthode que j’ai trouvée passe par WMI. Ainsi, pour connaître quand une orchestration se termine :


private void MountBTSOrchestrationMonitoring()
{
   // Only one watch to mount, because we can only monitor orchestration deletion
   WqlEventQuery q = new WqlEventQuery(__InstanceDeletionEvent,
                                       new TimeSpan(0,0,0,10),
                                       "TargetInstance isa \"MSBTS_ServiceInstance\"");
   m_btsWatcher = new ManagementEventWatcher(new ManagementScope(root/MicrosoftBizTalkServe),
                                             q);
   m_btsWatcher.EventArrived += new EventArrivedEventHandler(bts_OrchestrationDeleted);
   m_btsWatcher.Start();
}


private void bts_OrchestrationDeleted(object sender, EventArrivedEventArgs e)
{
   // Do something
}


Ainsi, lorsqu’une orchestration se terminera, l’événement bts_OrchestrationDeleted sera appelé. Le seul petit problème, c’est qu’il n’est pas possible de connaître quelle orchestration s’est terminée. Il faut alors interroger BizTalk, via WMI, à nouveau, pour savoir si une instance de l’orchestration observée est encore active :


private int OrchestrationInstanceCount(string strOrchestrationName)
{
   System.Text.StringBuilder sb = new System.Text.StringBuilder("SELECT * FROM MSBTS_ServiceInstance WHERE ServiceName=\"");
   sb.Append(strOrchestrationName);
   sb.Append("\"");
   WqlObjectQuery w = new WqlObjectQuery(sb.ToString());
   ManagementObjectSearcher objSearcher = new ManagementObjectSearcher(new ManagementScope(kstrWMIBTSNamespace),
                                                w);
   return objSearcher.Get().Count;
}


Si la méthode retourne 0, aucune orchestration avec le nom donné en paramètre n’est active.


Attention toute fois ! BizTalk met un certain temps avant de mettre en route une orchestration, faisant que même si un fichier est déposé dans un répertoire d’accueil de BizTalk, la méthode risque de renvoyer la valeur 0, car l’orchestration n’aura pas encore démarré. Il serait alors judicieux de voir si des fichiers sont encore présent dans le répertoire d’accueil avant d’en poster de nouveaux.


 


 





According to a lot of blogs, BizTalk has some issues with large files. However, despite of the efforts for rearchitecturing the application, it is sometimes not possible to avoid the OutOfMemoryException.


In the case of the actual project, that happens only when BizTalk has to process more than one file at a time. So, I temporary decided to pass to BizTalk only one file at a time and to wait the orchestration stops before copying the next file to the receive location. But, it seems that it is not possible to be warned when an orchestration stops with .NET.


The way I found is using WMI. To know when an orchestration stops, I install an event handler :


 


private void MountBTSOrchestrationMonitoring()
{
   // Only one watch to mount, because we can only monitor orchestration deletion
   WqlEventQuery q = new WqlEventQuery(__InstanceDeletionEvent,
                                       new TimeSpan(0,0,0,10),
                                       "TargetInstance isa \"MSBTS_ServiceInstance\"");
   m_btsWatcher = new ManagementEventWatcher(new ManagementScope(root/MicrosoftBizTalkServe),
                                             q);
   m_btsWatcher.EventArrived += new EventArrivedEventHandler(bts_OrchestrationDeleted);
   m_btsWatcher.Start();
}


private void bts_OrchestrationDeleted(object sender, EventArrivedEventArgs e)
{
   // Do something
}


When an orchestration will stop, the bts_OrchestrationDeleted event will be called. There is only one little issue. It is impossible to know which orchestration stopped. We have to get the answer from BizTalk itself, through WMI again, and getting the number of active instance with a given name :


 


private int OrchestrationInstanceCount(string strOrchestrationName)
{
   System.Text.StringBuilder sb = new System.Text.StringBuilder("SELECT * FROM MSBTS_ServiceInstance WHERE ServiceName=\"");
   sb.Append(strOrchestrationName);
   sb.Append("\"");
   WqlObjectQuery w = new WqlObjectQuery(sb.ToString());
   ManagementObjectSearcher objSearcher = new ManagementObjectSearcher(new ManagementScope(kstrWMIBTSNamespace),
                                                w);
   return objSearcher.Get().Count;
}


If the method returns 0, no orchestration with the given name is still running.


But, warning ! BizTalk needs a bit of time before starting an orchestration and event a file is dropped in a BizTalk receive location, the method will certainly return 0, because the orchestration is not yet started. It would be a good idea to test is there are files in the receive location before dropping new files.

Monday, July 04, 2005

Une fois un SQL-Server et un BizTalk Server 2004 installés, il est loin d'être trivial, ensuite, de modifier le nom du serveur hébergeant ces services.


Le service de Single Sign-On est d'ailleurs le plus embêtant à remettre sur ses pieds. Le plus simple restant encore à rechercher les occurences de l'ancien nom du serveur dans la base de registre et de les remplacer par le nouveau nom (en tout cas là où cela est pertinent...).


En revanche, l'exécution de l'outil de configuration de BTS2004 (ConfigFramework.exe) va échouer sur la modification des jobs que BTS2004 installe dans SQL-Server. La cause de l'erreur provient du fait que le serveur ayant généré ce job n'est plus le même que celui qui essaye de le modifier. Pour éviter ceci, il est possible d'exécuter la commande SQL suivante (dans le cas où il n'y aurait que des jobs BizTalk. Dans le cas contraire, il faudra filtrer la requête) :


UPDATE msdb.dbo.sysjobs SET originating_server = @@SERVERNAME WHERE
originating_server <> @@SERVERNAME


Ceci à pour effet de changer le nom du serveur original du job.


A noter que changer le nom d'un serveur hébergeant déjà des services tels que BizTalk n'est pas recommandé et ceci fait donc déjà partie des bidouilles...


 


Once SQL-Server and BizTalk Server 2004 installed, it is very hard to change the server name.


The Single Sign-On is one of the most difficult to fix afterward. The way I found is to search-and-replace all occurences of the old server name by the new one in the registry.


On the other hand, running the BTS2004 configuration tool (ConfigFramework.exe) will fail on the update of the BTS2004 SQL jobs. The root cause of this is that the server which generated these jobs is not the same as the one attempting to update them. To avoid this, it is possible to run the following SQL command (in the case of all jobs are Biztalk jobs. If not, you have to add a filter to your request) :


UPDATE msdb.dbo.sysjobs SET originating_server = @@SERVERNAME WHERE
originating_server <> @@SERVERNAME


This will change all originating server of all jobs.


Please notice that to change the server name hosting services like SQL-Server or BizTalk is absolutely not a recommended way...