Depuis le passage en .net10 : utilisation de Microsoft.Data.SqlClient

0000003412     -      22/01/2026

Depuis toujours, Mercator utilise System.Data.SqlClient pour communiquer avec le serveur SQL. Cette librairie est remplacée par Microsoft.Data.SqlClient. L'ancienne librairie est considérée par Microsoft comme étant en "mode maintenance" et ne recevra donc plus de nouvelles fonctionnalités.

Microsoft recommande de migrer vers la nouvelle librairie

  • pour des raisons de performances
  • parce que la sécurité de cette librairie est améliorée
  • parce qu'elle va permettre des développements orientés vers l'intelligence artificielle
  • ...

Plus d'informations à ce propos sur cette page.

Mercator Core compilé avec .net 10 utilise Microsoft.Data.SqlClient. Pour un Mercator sans code sur mesure, ce changement est totalement transparent. En revanche, tout code personnalisé qui utilise System.Data.SqlClient doit être adapté puisque ce Mercator ne connaîtra pas cette librairie. Cette migration doit être effectuée avec soin et en respectant la possibilité de fonctionner en mode hybride, càd dans une même configuration avec des Mercator en version classique ou .net Core 8.0.

Afin de fluidifier cette transition, Mercator apporte une série de nouvelles classes, méthodes et propriétés, qui permettent de rendre le code "agnostique" par rapport à la librairie utilisée. Autrement dit, ces classes, méthodes et propriétés existent de façon identique dans toutes les versions de Mercator (.net 4.8, .net 8.0 et .net 10.0). C'est leur implémentation interne qui détermine si System.Data.SqlClient ou Microsoft.Data.SqlClient est utilisé.


✅ Si le code sur mesure est destiné à être utilisé uniquement dans un Mercator Core .net 10.0, alors il suffit de remplacer partout dans ce code :

System.Data.SqlClient par Microsoft.Data.SqlClient

et de recompiler. La suite de cette page ne s'applique pas.


➡️ Sinon, de façon générale, la modification d'un code sur mesure commence par le retrait de la clause 

using System.Data.SqlClient;

qui se trouve dans le haut du code.

Si cette clause n'existe pas et si la chaîne "System.Data.SqlClient" ne se trouve pas dans ce code personnalisé, alors aucune modification ne doit être apportée.

Dans le cas contraire, le retrait de cette clause va provoquer quelques erreurs de compilations. Ce sont ces lignes qui devront être modifiées. Nous donnons ici quelques exemples de modifications à effectuer.

Zoom
using (SqlCommand cmd = new SqlCommand("insert into ..."))
{
    Api.SqlExec(Globals.RepData, cmd);
}

devient

Zoom
using (MercatorSqlCommand cmd = new MercatorSqlCommand("insert into ..."))
{
    Api.SqlExec(Globals.RepData, cmd);
}

👉 La classe SqlCommand appartient à l'espace de nom System.Data.SqlClient. Elle n'est donc plus utilisable. La classe MercatorSqlCommand se trouve dans MercatorApi. Ses paramètres sont identiques à ceux de SqlCommand mais elle est "agnostique" par rapport aux deux librairies. La méthode Api.SqlExec accepte indifféremment les deux types de commande.

 

Zoom
using (SqlCommand cmd = new SqlCommand(reqSql))
{
    cmd.Parameters.AddWithValue("@id", currentUserId).SqlDbType = SqlDbType.Char;
    Api.SqlExec(MercatorUi.Globals.RepData, cmd);
}

devient

Zoom
Api.SqlExec(MercatorUi.Globals.RepData, reqSql, new MercatorSqlParam("@id", currentUserId, SqlDbType.Char));

👉 Ici, on procède à une simplification du code qui ne nécessite plus d'utiliser SqlCommand.

 

Zoom
using (MercatorSqlConnection conn = new MercatorSqlConnection(Globals.RepData, true))
{
    if (conn.Connection == null)
        return;
    using (SqlTransaction transac = conn.Connection.BeginTransaction())
    {
        using (SqlCommand cmd = new SqlCommand("update ... delete ...", conn.Connection, transac))
        {
            if (!Api.SqlExec(cmd))
                Api.SafeRollback(transac);
            else
                Api.SafeCommit(transac);
        }
    }
}

devient

Zoom
using (MercatorSqlConnection conn = new MercatorSqlConnection(Globals.RepData, true))
{
    if (!conn.IsConnected)
        return;
    using (MercatorSqlCommand cmd = new MercatorSqlCommand("update ... delete ..."))
    {
        Api.SqlExec(conn, cmd, underTransaction: true);
    }
}

👉 Ici, on procède à une simplification du code qui ne nécessite plus d'utiliser SqlTransaction.

 

Zoom
MercatorSqlParam mySqlParam = Api.SqlParamsGlobal.FindByParamName("@myParam");
if (mySqlParam == null)
    Api.SqlParamsGlobal.Add(new MercatorSqlParam("@myParam", "xx", SqlDbType.Char));
else
    mySqlParam.pSql.Value = "xx";

devient

Zoom
MercatorSqlParam mySqlParam = Api.SqlParamsGlobal.FindByParamName("@myParam");
if (mySqlParam == null)
    Api.SqlParamsGlobal.Add(new MercatorSqlParam("@myParam", "xx", SqlDbType.Char));
else
    mySqlParam.Value = "xx";

👉 Ici, on retire simplement .pSql car il dépend de System.Data.SqlClient ou de Microsoft.Data.SqlClient. L'accesseur direct .Value renvoie la même valeur.

 

Zoom
billingEngine.CommandForFinalTransaction = new System.Data.SqlClient.SqlCommand("...");
billingEngine.CommandForInitialTransaction = new System.Data.SqlClient.SqlCommand("...");

devient

Zoom
billingEngine.MercatorSqlCommandForFinalTransaction = new MercatorSqlCommand("...");
billingEngine.MercatorSqlCommandForInitialTransaction = new MercatorSqlCommand("...");

👉 Ici, on utilise des nouvelles propriétés du BillingEngine qui ne dépendent ni de System.Data.SqlClient, ni de Microsoft.Data.SqlClient. Ce même principe s'applique à tous les engines de Mercator.

⚠️ MercatorSqlCommandForFinalTransaction n'est pas une commande supplémentaire, en plus de CommandForFinalTransaction. Il s'agit simplement d'un accesseur permettant de populer CommandForFinalTransaction. Il ne faut donc jamais mettre une valeur dans les deux propriétés en même temps. Le même principe s'applique à InitialTransaction.

 

Zoom
private void BillingEngine_DuringSave(object sender, MercatorUi.Engine.Gescom.BillingEngine.DuringSaveEventArgs e)
{
    MercatorUi.Engine.Gescom.BillingEngine billingEngine = (MercatorUi.Engine.Gescom.BillingEngine)sender;
    e.SqlCommand.CommandText = "update ...";
    e.SqlCommand.Parameters.AddWithValue("@param", "...");
}

devient

Zoom
private void BillingEngine_DuringSave(object sender, MercatorUi.Engine.Gescom.BillingEngine.DuringSaveEventArgs e)
{
    MercatorUi.Engine.Gescom.BillingEngine billingEngine = (MercatorUi.Engine.Gescom.BillingEngine)sender;
    e.MercatorSqlCommand.CommandText = "update ...";
    e.MercatorSqlCommand.Parameters.AddWithValue("@param", "...");
}

👉 Ici, on utilise des nouvelles propriétés de l'eventArgs qui ne dépendent ni de System.Data.SqlClient, ni de Microsoft.Data.SqlClient. Ce même principe s'applique à tous les engines de Mercator.

⚠️ MercatorSqlCommand n'est pas une commande supplémentaire, en plus de SqlCommand. Il s'agit simplement d'un accesseur permettant de populer SqlCommand. Il ne faut donc jamais mettre une valeur dans les deux propriétés en même temps.

 

Zoom
public class Customizer : MercatorUi.ICustomizers.ISqlCommandUpdater
{
    public void SqlCommandUpdate(SqlCommand sqlCommandToModify, Form form)
    {
        sqlCommandToModify.CommandText = "... \r\n"
                                       + sqlCommandToModify.CommandText;
    }
}

devient

Zoom
public class Customizer : MercatorUi.ICustomizers.IMercatorSqlCommandUpdater
{
    public void MercatorSqlCommandUpdate(MercatorSqlCommand sqlCommandToModify, Form form)
    {
        sqlCommandToModify.CommandText = "... \r\n"
                                       + sqlCommandToModify.CommandText;
    }
}

👉 Ici, on utilise, on remplace simplement l'interface ISqlCommandUpdater par IMercatorSqlCommandUpdater.

 

Zoom
void billingEngine_BeginningSave(object sender, MercatorUi.Engine.Gescom.BillingEngine.BeginningSaveEventArgs e)
{
    MercatorUi.Engine.Gescom.BillingEngine billingEngine = (MercatorUi.Engine.Gescom.BillingEngine)sender;
    using (SqlCommand cmd = new SqlCommand("...", e.Connection, e.Transaction))
    {
        ...
    }
}

devient

Zoom
void billingEngine_BeginningSave(object sender, MercatorUi.Engine.Gescom.BillingEngine.BeginningSaveEventArgs e)
{
    MercatorUi.Engine.Gescom.BillingEngine billingEngine = (MercatorUi.Engine.Gescom.BillingEngine)sender;
    using (MercatorSqlCommand cmd = new MercatorSqlCommand("...", e.Connection, e.DbTransaction))
    {
        ...
    }
}

👉 Notez l'utilisation de e.DbTransaction qui est de type System.Data.Common.DbTransaction, qui est une classe parente à la fois de System.Data.SqlClient.Transaction et Micrsosoft.Data.SqlClient.Transaction.

 

Voir aussi : Accès asynchrone à la base de données SQL avec l'API de Mercator

 

Si ce qui précède ne suffit pas, le compilateur intégré de Mercator reconnaîtra la clause #if NET10_0_OR_GREATER afin de produire deux assemblies disctinctes. L'une compilée pour System.Data.SqlClient, l'autre pour Microsoft.Data.SqlClient. A l'exécution, en fonction de la version utilisée, Mercator choisir l'assembly à utiliser.

Zoom
using System.Data.SqlClient;

devient

Zoom
#if NET10_0_OR_GREATER
using Microsoft.Data.SqlClient;
#else
using System.Data.SqlClient;
#endif

⚠️ Cette méthode souffre de la limite suivante : MercatorTunnel.dll et MercatorUi.dll passées en référence lors de la compilation sont toujours celles de la version en cours d'exécution. Ceci empêchera la compilation de codes qui, par exemple, utilisent des propriétés de classes dans MercatorUi qui font elle-même référence à System.Data.SqlClient ou Microsoft.Data.SqlClient.

 

Enfin, si on parle de code se trouvant dans un projet externe compilé depuis Visual Studio, l'utilisation des classes, méthodes et propriétés "agnostiques" est aussi possible. Une autre façon de procéder consiste à produire 2 assemblies en activant la compilation multiplateforme. Pour cela, dans le projet (préalablement migré vers le format SDK), remplacez

<TargetFramework>net48</TargetFramework>
par
<TargetFrameworks>net48;net10.0-windows</TargetFrameworks>

Indiquez les références correctement pour chaque version.

Zoom
<ItemGroup Condition=" '$(TargetFramework)' == 'net48' ">
  <Reference Include="MercatorComponents">
    <HintPath>C:\DossiersClientsRefAssemblies\fw40\MercatorComponents.dll</HintPath>
  </Reference>
  <Reference Include="MercatorTunnel">
    <HintPath>C:\DossiersClientsRefAssemblies\fw40\MercatorTunnel.dll</HintPath>
  </Reference>
  <Reference Include="MercatorUi">
    <HintPath>C:\DossiersClientsRefAssemblies\fw40\MercatorUi.dll</HintPath>
  </Reference>
</ItemGroup>

<ItemGroup Condition=" '$(TargetFramework)' == 'net10.0-windows' ">
  <Reference Include="MercatorComponents">
    <HintPath>C:\DossiersClientsRefAssemblies\fw100\MercatorComponents.dll</HintPath>
  </Reference>
  <Reference Include="MercatorTunnel">
    <HintPath>C:\DossiersClientsRefAssemblies\fw100\MercatorTunnel.dll</HintPath>
  </Reference>
  <Reference Include="MercatorUi">
    <HintPath>C:\DossiersClientsRefAssemblies\fw100\MercatorUi.dll</HintPath>
  </Reference>
  <PackageReference Include="Microsoft.Data.SqlClient" Version="6.1.3" />
</ItemGroup>

⚠️ Adaptez les chemins vers les DLL et référencez toujours la DLL compilée pour le framework adéquat. Les versions des DLL de Mercator se reconnaissent par le dernier nombre qui indique la version du framework.

Enfin, remplacez partout dans le code

Zoom
using System.Data.SqlClient;

par

Zoom
#if NET10_0_OR_GREATER
using Microsoft.Data.SqlClient;
#else
using System.Data.SqlClient;
#endif

La compilation va produire deux assemblies que vous pouvez placer dans "Gestion / Fichiers SQL / Assemblies". Lors de son démarrage, Mercator téléchargera la bonne version en fonction de la version utilisée.

 


La requête SQL ci-dessous permet de lister les codes C# stockés dans la base de données, contenant System.Data.SqlClient :

select id,code from ASSEMBLIES where code like '%System.Data.SqlClient%'


Cookies fonctionnels : Cookies nécessaires à l'utilisation du site et cookies de préférence. Ils ne contiennent aucune donnée à caractère personnel. (En savoir plus)

Cookies statistiques : Captation de statistiques liées aux comportements des internautes. (En savoir plus)

Cookies marketing : Pour effectuer le suivi des visiteurs au travers des sites web, à des fins publicitaires. (En savoir plus)