Vous consultez une page technique concernant le logiciel de gestion Mercator. Celle-ci contient des informations spécifiques destinées aux professionnels de Mercator. Souhaitez-vous être redirigés vers des informations plus générales ?


   Ne plus poser cette question

Utilisation des méthodes Api.Zselect typées

0000002752     -      03/10/2017

Depuis toujours, Mercator propose un jeu complet de méthodes Api.Zselect() pour obtenir des données de la base de données SQL sous la forme d'un DataSet. Il est à présent possible d'utiliser les mêmes méthodes en version typée, Api.Select<T>(), pour obtenir directement une List<T>. L'avantage est que le résultat correspondant à chaque colonne sera typé, ce qui permet d'éviter de devoir écrire les conversions, de profiter du confort d'intellisense et de la sécurité qu'offre le contrôle des types du compilateur.

Afin de pouvoir utiliser une méthode Zselect typée, il faut définir une classe d'objet qui correspond aux données qui seront extraites par la requête SQL.

Dans l'exemple qui suit, nous souhaitons obtenir une liste des clients, avec ces informations :

  • L'ID du client
  • Son nom
  • Son régime
  • Pour sa dernière vente :
    • La date
    • Le type de vente (1 = facture, 2 = livraison, ...)
    • La référence.

Si le client n'a jamais fait l'objet d'une vente, nous souhaitons que les 3 dernières valeurs soient null.

Il convient dans un premier temps de définir une classe qui correspond à la structure des informations qui seront récupérées de la base de données. :

Zoom
public class CLI_LAST_SALE
{
    public string C_ID { get; set; }
    public string C_NOM { get; set; }
    public Int16 C_REGIME { get; set; }
    public DateTime? DATE { get; set; }
    public Int16? TYPE { get; set; }
    public string REFERENCE { get; set; }
}

 

Ensuite, le code qui va produire le résultat est simplement le suivant :

Zoom
string reqSql = @"
    select * into #pvtmp from (
        select id,journal,piece,id_cli,date,reference,type,ROW_NUMBER() OVER (PARTITION BY p2.id_cli ORDER BY p2.date desc,p2.type desc) as rn from pieds_v p2
        ) t
    where rn=1

    select c.C_ID,c.C_NOM,c.C_REGIME,p.DATE,p.TYPE,p.REFERENCE from CLI c
        left join #pvtmp p on (c.c_id=p.id_cli)

    drop table #pvtmp";

List<CLI_LAST_SALE> l = Api.Zselect<CLI_LAST_SALE>(MercatorUi.Globals.RepData, reqSql);

 

Si l'extraction des données ne peut avoir lieu (erreur SQL) ou si le mapping vers la classe passée en tant que type ne peut être effectué, alors le retour de Zselect<T>() sera null. Il convient de toujours tester ce cas.

Lors de la conception de la classe, il faut tenir compte de ceci :

  • Le nom des propriétés doit être strictement égal au nom de la colonne renvoyée par la requête SQL. Cette comparaison est case sensitive. Le cas échéant, utilisez
    • select MON_CHAMP
    • ou select mon_champ as MON_CHAMP si la propriété dans la classe est MON_CHAMP en majuscules.
  • Le mapping entre les types SQL et les types .net doit être respecté scrupuleusement.
    • bigint = Int64
    • binary = Byte[]
    • bit = Boolean
    • char = String
    • date = DateTime
    • datetime = DateTime
    • decimal = Decimal
    • float = Double
    • image = Byte[]
    • int = Int32
    • nchar = String
    • numeric = Decimal
    • nvarchar = String
    • smallint = Int16
    • tinyint = Byte
    • uniqueidentifier = Guid
    • varbinary = Byte[]
    • varchar = String
  • Lors du choix des types, il faut déterminer si la propriété est susceptible de contenir des valeurs null ou pas. C'est le cas si la colonne SQL autorise le stockage de null ou, par exemple, lors d'une jointure (left ou right), quand aucun enregistrement correspondant n'est trouvé. Certains types, tels que String, Byte[] peuvent toujours stocker une valeur null. Dans ce cas, il ne faut donc rien prévoir de particulier. En ce qui concerne les types "valeurs", le cas échéant, il faut indiquer que le type est nullable, en lui ajoutant un ?. Par exemple Int16?, DateTime?, ... Dans l'exemple ci-dessus, REGIME n'est pas nullable car il est certain qu'aucune valeur null ne devra y être stockée, alors que TYPE doit l'être (cas où aucune vente n'a été effectuée pour ce client).
  • La classe et toutes les propriétés qui doivent être associées à des résultats doivent être publiques.
  • Dans la classe, il faut utiliser des propriétés { get; set; } et non de simples champs.
  • La classe peut contenir d'autres propriétés, champs ou méthodes. Ceux-ci seront ignorés. Si elle contient un constructeur, elle doit contenir un constructeur n'exigeant aucun paramètre.
  • La requête SQL peut renvoyer des colonnes supplémentaires par rapport aux propriétés publiques de la classe de mapping. Elles seront simplement ignorées.

 

Les propriétés de type String sont automatiquement trimmées à droite lors de leur affectation.

 

Comme pour la version non typée, toute une série de signatures sont disponibles :

Zoom
public static List<T> Zselect<T>(SqlConnection cnn, SqlCommand cmd, MercatorSqlParam[] pp, SqlTransaction transaction, bool withSchema);
public static List<T> Zselect<T>(SqlConnection conn, SqlCommand cmd, MercatorSqlParam[] pp, SqlTransaction Transaction);
public static List<T> Zselect<T>(SqlConnection conn, SqlCommand cmd, MercatorSqlParam[] pp);
public static List<T> Zselect<T>(SqlConnection conn, SqlCommand cmd, List<MercatorSqlParam> listPp, SqlTransaction transaction);
public static List<T> Zselect<T>(SqlConnection conn, SqlCommand cmd, List<MercatorSqlParam> listPp);
public static List<T> Zselect<T>(SqlConnection conn, SqlCommand cmd, MercatorSqlParam p1 = null, MercatorSqlParam p2 = null, MercatorSqlParam p3 = null, MercatorSqlParam p4 = null, MercatorSqlParam p5 = null, MercatorSqlParam p6 = null, MercatorSqlParam p7 = null, MercatorSqlParam p8 = null, MercatorSqlParam p9 = null);
public static List<T> Zselect<T>(MercatorSqlConnection conn, string reqSql, List<MercatorSqlParam> listPp);
public static List<T> Zselect<T>(MercatorSqlConnection conn, string reqSql, MercatorSqlParam[] pp);
public static List<T> Zselect<T>(MercatorSqlConnection conn, string reqSql, MercatorSqlParam p1 = null, MercatorSqlParam p2 = null, MercatorSqlParam p3 = null, MercatorSqlParam p4 = null, MercatorSqlParam p5 = null, MercatorSqlParam p6 = null, MercatorSqlParam p7 = null, MercatorSqlParam p8 = null, MercatorSqlParam p9 = null);
public static List<T> Zselect<T>(string repData, string reqSql, MercatorSqlParam[] pp, bool withSchema);
public static List<T> Zselect<T>(string repData, string reqSql, MercatorSqlParam[] pp);
public static List<T> Zselect<T>(string repData, string reqSql, List<MercatorSqlParam> listPp, bool withSchema);
public static List<T> Zselect<T>(string repData, string reqSql, List<MercatorSqlParam> listPp);
public static List<T> Zselect<T>(string repData, string reqSql, MercatorSqlParam p1 = null, MercatorSqlParam p2 = null, MercatorSqlParam p3 = null, MercatorSqlParam p4 = null, MercatorSqlParam p5 = null, MercatorSqlParam p6 = null, MercatorSqlParam p7 = null, MercatorSqlParam p8 = null, MercatorSqlParam p9 = null);
public static List<T> Zselect<T>(string repData, SqlCommand Comm);

 

Contrairement à la version non typée, qui peut renvoyer un DataSet contenant plusieurs DataTables, cette version ne peut renvoyer qu'un seul jeu de données (une seule liste, donc l'équivalent d'une seule DataTable). Si plusieurs jeux de données doivent être renvoyés, nous suggérons d'utiliser cette structure de code, qui permet de ne se connecter qu'une seule fois au serveur SQL :

Zoom
void DoSomething()
{
    using (MercatorSqlConnection conn = new MercatorSqlConnection(MercatorUi.Globals.RepData, true))
    {
        if (conn.Connection == null)
            return;
        List<T1> l1 = Api.Zselect<T1>(conn, "select ... from TABLE1 where ...");
        List<T2> l2 = Api.Zselect<T2>(conn, "select ... from TABLE2 where ...");
    }
}

public class T1
{
    public string Prop1 { get; set; }
    public string ...
}
public class T2
{
    public string Prop1 { get; set; }
    public string ...
}

 

Nous rappelons qu'il est possible de placer le code d'une classe de mappage directement dans un customizer. Cela peut se faire, par exemple, avant la seconde accolade (fermante) par le bas du code. Cela produit ainsi une classe imbriquée dans la classe du customizer, qui sera utilisable par Api.Zselect<T>().

ExempleCharger les images dans la base de données SQL