Accueil Blog (en) 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 la rédaction : Le contenu de cet article a été mis à jour par l’un de nos MVP développeurs - Kyle Vanderstoep - le mettant en conformité avec la plate-forme d’expédition actuelle, y compris les extraits de code présents dans le post. (Publié à l’origine le 6 décembre 2018)
Mark Franks | Mai 23, 2022

Dans cet article, nous fournirons une introduction de base à notre langage de requête d’entreprise fluide qui est une technologie complémentaire à BQL. Mais avant de le faire, nous allons avoir un peu d’un examen de notre Langage de requête d’affaires (BQL) fournissant un peu de contexte pour ceux d’entre vous qui lisent ce post qui peuvent être nouveaux à la plate-forme Acumatica.

Fluent BQL - Augmentez 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 du cadre Acumatica. Les instructions BQL représentent un ensemble spécifique de requêtes Acumatica qui sont traduites dans le SQL approprié requis par la base de données principale par l’infrastructure.  Cela protège le développeur des nuances de langage inhérentes à divers fournisseurs de bases de données (permettant à Acumatica d’être indépendant de la base de données) et valide ces requêtes au moment de la compilation.

BQL résout deux problèmes discrets et plutôt importants auxquels les développeurs sont souvent confrontés.  Premièrement, un moyen simple de créer des requêtes à partir d’un ensemble de primitives prédéfinies, et deuxièmement, la déclaration de requêtes à un niveau d’attribut en C#. Les deux problèmes sont résolus par l’utilisation de types génériques.

Les séquences d’éléments de même niveau dans BQL sont implémentées de manière très similaire à une structure de liste liée, où chaque élément suivant doit être passé en tant que paramètre générique du précédent. Cela permet à un développeur de créer une requête en combinant des éléments primitifs ensemble sans nombreuses limites.  Pourtant, souvent pour que cette flexibilité se manifeste, un développeur sacrifiera la lisibilité, et donc 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, au lieu d’essayer d’analyser et de modifier les plus anciennes. Si nous sommes honnêtes, nous ne pouvons pas vraiment les blâmer! Contrairement à un ordinateur, une personne ne peut pas facilement analyser les structures fortement imbriquées, surtout lorsqu’il n’y a pas de besoin spécifique d’une structure imbriquée.

Il existe d’autres problèmes avec BQL tels que la surcharge « numérotée » des composants de requête de base, plusieurs familles de classes de sélection avec des structures qui se chevauchent, ainsi que le problème de l’équilibrage des crochets d’angle des classes génériques, en corrélation assez faible avec les parenthèses des requêtes SQL natives.

Tous ces problèmes soulignent le fait que BQL nous fournit un moyen 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ésoudre ces problèmes, l’une de nos équipes d’ingénierie 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 classe génériques de type fonction, Fluent BQL utilise des déclarations de classe générique fluent, basées sur l’imbrication de classes génériques. Cela divise et organise naturellement les composants les plus importants d’une requête tels que les jointures et les agrégats, et supprime complètement l’ambiguïté des noms de commandes. La structure de requête ressemble davantage à la structure SQL, où chaque section ne dépend pas des autres et ne peut apparaître que dans les endroits qui lui sont attribués. L’imbrication de 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 prendre une classe de surcharge de commande appropriée.  Au lieu de cela, commencez simplement à taper une commande et IntelliSense offrira des continuations pertinentes pour l’état actuel de la requête. En outre, il convient de noter que les sections d’une requête ne sont pas séparées par des virgules, ce qui est une bonne chose car elles ne sont pas égales dans un certain sens, et 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 de base Acumatica et les champs de tous les DAC sont déjà compatibles avec les comparaisons fluides.

Conditions fluentes

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 crochets explicites pour les conditions, mais les crochets peuvent être ajoutés 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 crochets explicites conduit à une représentation non évidente, contre-intuitive et difficile à maintenir des conditions.

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 a également des conditions plus complexes très utiles qui ne sont pas disponibles (ou rendues plus faciles à utiliser).

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 l’agrégation sont en lecture seule par défaut.

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

Clés étrangères dans FBQL

Une autre fonctionnalité très pratique lors de la conception d’une requête avec beaucoup de jointures est les nouvelles définitions de clés étrangères présentes sur les DAC. Cela accélérera la programmation d’une requête volumineuse qui interroge de nombreuses tables. Jetons d’abord un coup d’œil à la façon dont ils sont définis dans le DAC :

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

À l’intérieur de la classe FK définit 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. Jetons un coup d’œil à la façon dont cela est défini ici:

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 bouleversant ici, où la clé étrangère / primaire n’est qu’un seul champ, mais dans les cas où il s’agit d’une clé composite composée de 2 ou 3 champs, cela peut réduire considérablement la taille de la requête.

FBQL est dérivé de BQL

Les trois directives simples suivantes que FBQL met en œuvre aident à augmenter considérablement la lisibilité et la maintenabilité des requêtes FBQL par rapport aux requêtes BQL classiques.

  1. Utilisez 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 contenants (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 de recherches et de vues uniques basées sur la famille Select, 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 cet article à vous présenter l’une de nos offres de technologie de développeur, le langage de requête d’affaires Fluent - FBQL, et nous espérons avoir articulé sa valeur pour les développeurs de création d’applications et d’intégrations avec la plate-forme ERP robuste basée sur le cloud d’Acumatica.  FBQL aidera les développeurs à maintenir une bibliothèque de requêtes en les rendant beaucoup plus faciles à lire. Ceci est accompli fondamentalement en changeant la structure inhérente du langage BQL lui-même.  Il ne remplace pas BQL, en soi, mais offre un langage de requête gratuit 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 éventail de requêtes complexes.

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

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

Nous espérons que cela a été utile - surtout maintenant que cet article a été mis à jour depuis notre publication initiale en 2018.

Bon codage!



                

Articles connexes

Auteur du blog

Mark était l’ancien directeur principal des relations avec les développeurs chez Acumatica.

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