Accueil Blog Fluent BQL- Augmentez la lisibilité et la maintenabilité de vos requêtes

Fluent BQL- Augmentez la lisibilité et la maintenabilité de vos requêtes

Note de l'éditeur : Le contenu de cet article a été mis à jour par l'un de nos développeurs MVP - Kyle Vanderstoep - afin de l'aligner sur la plateforme de livraison actuelle, y compris les extraits de code présents dans l'article. (Publié initialement le 6 décembre 2018)
Mark Franks | Mai 23, 2022

Dans ce billet, nous présenterons une introduction de base à notre langage Fluent Business Query Language qui est une technologie complémentaire à BQL. Mais avant cela, nous allons passer en revue notre Business Query Language (BQL) afin de fournir un contexte à ceux d'entre vous qui lisent ce billet et qui ne connaissent pas encore la plateforme Acumatica.

Fluent BQL- Améliorez la lisibilité et la maintenabilité de vos requêtes

Pour interroger et manipuler les données de la base de données Acumatica, un développeur utilisera BQL - qui fait partie de la couche d'accès aux données de l'Acumatica Framework. Les instructions BQL représentent un ensemble spécifique de requêtes Acumatica qui sont traduites dans le langage SQL approprié requis par la base de données back-end du framework. Cela protège le développeur des nuances de langage inhérentes aux différents fournisseurs de bases de données (permettant à Acumatica d'être agnostique en matière de bases de données), et valide ces requêtes au moment de la compilation.

BQL résout deux problèmes discrets et relativement importants auxquels les développeurs sont souvent confrontés. D'une part, un moyen simple de créer des requêtes à partir d'un ensemble de primitives prédéfinies et, d'autre part, la déclaration des requêtes au niveau des attributs en C#. Ces deux problèmes sont résolus par l'utilisation de types génériques.

Les séquences d'éléments de même niveau en BQL sont mises en œuvre de manière très similaire à une structure de liste liée, où chaque élément suivant doit être transmis en tant que paramètre générique de l'élément précédent. Cela permet à un développeur de construire une requête en combinant des éléments primitifs sans trop de limites. Cependant, pour que cette flexibilité se manifeste, le développeur doit souvent sacrifier la lisibilité et, par conséquent, la maintenabilité.

GIST:

https://gist.github.com/lekker-solutions/61240fcb5b8d2595cb2e3655329e4827

Il n'est pas étonnant que les développeurs préfèrent réécrire la plupart de leurs requêtes BQL à partir de zéro, plutôt que d'essayer d'analyser et de modifier les anciennes. Si nous sommes honnêtes, nous ne pouvons pas vraiment les blâmer ! Contrairement à un ordinateur, une personne ne peut pas facilement analyser des structures fortement imbriquées, en particulier lorsqu'une structure imbriquée n'est pas nécessaire.

Il existe d'autres problèmes avec BQL, tels que la surcharge "numérotée" des composants de la requête de base, les multiples familles de classes de sélection dont les structures se chevauchent, ainsi que le problème de l'équilibre des crochets d'angle des classes génériques, dont la corrélation avec les parenthèses des requêtes SQL natives est plutôt médiocre.

Tous ces problèmes montrent que le langage BQL nous permet de produire une variété infinie de requêtes. Pour les développeurs, cependant, il est très difficile de lire et de maintenir des requêtes BQL complexes, principalement en raison de la structure du langage BQL lui-même.

Pour répondre à ces problèmes, l'une de nos équipes d'ingénieurs chez Acumatica a trouvé une solution en créant Fluent BQL.

Qu'est-ce que Fluent BQL ?

Contrairement à BQL, qui utilise des déclarations de classes génériques de type fonction, Fluent BQL utilise des déclarations de classes génériques fluentes, basées sur l'imbrication des classes génériques. Ceci divise et organise naturellement les composants les plus élevés d'une requête tels que les jointures et les agrégats, et élimine complètement l'ambiguïté des noms de commandes. La structure de la requête ressemble davantage à la structure SQL, où chaque section ne dépend pas des autres et ne peut apparaître qu'aux endroits qui lui sont assignés. L'imbrication des classes dans une définition de commande permet de réduire l'imbrication des composants dans une déclaration de commande.

En utilisant FBQL, un développeur n'a pas besoin de choisir une classe de surcharge de commande appropriée. Il lui suffit de taper une commande et IntelliSense lui proposera des continuations pertinentes pour l'état actuel de la requête. Il convient également de noter que les sections d'une requête ne sont pas séparées par des virgules, ce qui est une bonne chose puisqu'elles ne sont pas égales dans un certain sens et que leur nombre ne peut varier que dans des limites très discrètes.

Now let’s take a look at some code to get a peek at FBQL.   With fluent comparisons, a developer has to use PX.Data.BQL.Bql[Type].Field<TSelf> as a base class for the field as illustrated below. This is already the default all across Acumatica today, however, you might find legacy code written by third parties that still have the IbqlField interface instead.

GIST: https://gist.github.com/lekker-solutions/0379133b6b0432e1717fc5e70a0dc005

Notez que toutes les constantes du noyau Acumatica et les champs de tous les DAC sont déjà compatibles avec les comparaisons fluentes.

Conditions de fluidité

The Fluent conditions approach uses dot-separated chaining of Tunary conditions. All IbqlUnary classes, including fluent comparisons, of the Acumatica core, can be used with fluent conditions. To append a condition to another one, just use .And<Tunary> or .Or<Tunary> nested classes of the first condition expression.

GIST: https://gist.github.com/lekker-solutions/731f0b2462c5927b97851f4bd1ea61ce

BQL n'a pas de parenthèses explicites pour les conditions, mais des parenthèses pourraient être ajoutées en enveloppant une partie d'une condition dans une clause Where supplémentaire, ce qui n'est pas une tâche triviale. Avec les modèles de chaînage, l'absence de parenthèses explicites conduit à une représentation des conditions non évidente, contre-intuitive et difficile à maintenir.

FBQL brings a brackets class, which represents explicit brackets.  Further, what is pretty exciting is that now parentheses are represented by angle brackets of the new fluent .And<> and .Or<> classes. Because of this, there is only one case when you may need to use a brackets class explicitly ‒‒ it is when you start your condition with something enclosed in parentheses. If .And<> or .Or<> contains a single comparison, it does not become wrapped in parentheses.

GIST : https://gist.github.com/lekker-solutions/f931b92916d7c8fecc3870b75d065dd2

FBQL dispose également de conditions plus complexes très utiles qui ne sont pas disponibles (ou dont l'utilisation est facilitée).

GIST: https://gist.github.com/lekker-solutions/36524f61e4dc38635c1e17425be25d8a

Quelques comparaisons entre FBQL et BQL

 

FluentBQL

* Joins are not actually a section of a query, in comparison to other its sections such as Where<>, Aggregate<>, and OrderBy<>, that are containers for some query elements.

** Toutes les vues qui contiennent des agrégations sont en lecture seule par défaut.

GIST : https://gist.github.com/lekker-solutions/cde0f434d8e111e3a1b18eeb655d6e01

Clés étrangères dans FBQL

Les nouvelles définitions de clés étrangères présentes dans les CAD constituent une autre fonctionnalité très pratique lors de la conception d'une requête comportant de nombreuses jointures. Cela accélérera la programmation d'une grande requête qui interroge un grand nombre de tables. Voyons d'abord comment elles sont définies dans le CAD :

GIST : https://gist.github.com/lekker-solutions/e37513feb79b7b9b5b5f2db1c449373a

La classe FK contient une autre classe, InventoryItemFK, qui spécifie que PAModelGenXRef.inventoryID est une référence de clé étrangère à la clé primaire (PK) de la table InventoryItem. Voyons comment cela est défini :

GIST: https://gist.github.com/lekker-solutions/73d00938acf89275f6e454f05f796ba3

Nous pouvons utiliser ces définitions dans FBQL.

GIST: https://gist.github.com/lekker-solutions/e17021994eed8e0fbd356bc857fecfbd

Cela n'est peut-être pas très important dans le cas où la clé étrangère/primaire ne comporte qu'un seul champ, mais lorsqu'il s'agit d'une clé composite composée de 2 ou 3 champs, cela peut réduire la taille de la requête de manière significative.

L'IQFB est dérivée de l'IQB

Les trois directives simples suivantes mises en œuvre par FBQL permettent d'améliorer considérablement la lisibilité et la maintenabilité des requêtes FBQL par rapport aux requêtes BQL classiques.

  1. Utiliser un modèle de déclaration de classe générique fluide, au lieu d'un modèle de déclaration de classe générique classique de type fonction.
  2. Utilisez des conteneurs (ou des tableaux) de composants plutôt que des chaînes (ou des listes liées) de composants.
  3. Utilisation d'une famille de sélections et d'une recherche et de vues uniques basées sur la famille de sélections, au lieu de trois familles similaires.

Yet it is important to keep in mind that FBQL doesn’t replace BQL – FBQL complements it!  They can be used together in the same file or class, or even query (you can use FBQL . Where<> in a Bql Where statement, etc, without any naming conflicts. Moreover, FBQL is based on BQL, since the FBQL-command delegates all the querying work to a corresponding BQL-command. All that FBQL tries to achieve is a much higher level of convenience for developers.

 

Résumé

Nous avons passé du temps dans ce billet à vous présenter l'une de nos offres technologiques pour les développeurs, le Fluent Business Query Language - FBQL, et nous espérons avoir articulé sa valeur pour les développeurs qui construisent des applications et des intégrations avec la robuste plateforme ERP basée sur le Cloud d'Acumatica. FBQL aidera les développeurs à maintenir une bibliothèque de requêtes en les rendant beaucoup plus facilement lisibles. Cela se fait fondamentalement en modifiant la structure inhérente du langage BQL lui-même. Il ne remplace pas BQL en soi, mais offre un langage de requête complémentaire qui peut être utilisé ensemble, de manière pratique, permettant aux développeurs d'augmenter leur efficacité dans l'écriture et la maintenance d'un ensemble de requêtes complexes.

Voici un résumé des principales caractéristiques :

  • Utilisation d'un modèle de déclaration de classe générique fluide, au lieu d'un modèle de déclaration de classe générique classique de type fonctionnel ;
  • Séparation intuitive des sections de la requête ;
  • Amélioration, simplification et intuitivité de l'élaboration des conditions ;
  • Champs/constantes/fonctions fortement typés et vérification statique des types dans les conditions ;
  • Utilisation d'options/indices au lieu de surcharges numérotées de composants de requête ;
  • Opérations binaires infixes ;
  • L'équilibre naturel des crochets d'angle ; et
  • Prise en charge native d'IntelliSense.

Nous espérons que ces informations vous ont été utiles, d'autant plus que ce billet a été mis à jour depuis sa publication initiale en 2018.

Bon codage !



                

Articles connexes

Auteur du blog

Mark était auparavant responsable des relations avec les développeurs chez Acumatica.

Recevez les mises à jour du blog dans votre boîte de réception.