Utilisation du cadre SysExtension pour savoir quelle sous-classe instancier dans Dynamics AX 2012
Publié : 16 février 2025 à 00 h 30 min 16 s UTC
Dernière mise à jour : 12 janvier 2026 à 08 h 43 min 56 s UTC
Cet article décrit comment utiliser le cadre peu connu SysExtension dans Dynamics AX 2012 et Dynamics 365 for Operations pour instancier des sous-classes basées sur des décorations d’attributs, permettant ainsi une conception facilement extensible d’une hiérarchie de classes de traitement.
Using the SysExtension Framework to Find Out Which Subclass to Instantiate in Dynamics AX 2012
Les informations contenues dans ce billet sont basées sur le Dynamics AX 2012 R3. Cela peut être valide ou non pour d’autres versions. (Mise à jour : Je peux confirmer que les informations de cet article sont également valides pour Dynamics 365 for Operations)
Lorsque vous implémentez des classes de traitement dans Dynamics AX, vous êtes souvent confronté à créer une hiérarchie de classes où chaque sous-classe correspond à une valeur enum ou possède un autre couplage de données. Un design classique consiste alors à avoir une méthode construct dans la superclasse, qui possède un interrupteur qui détermine quelle classe instancier selon l’entrée.
Cela fonctionne bien en principe, mais si vous avez plusieurs entrées possibles différentes (beaucoup d’éléments dans un enum ou peut-être que l’entrée est une combinaison de plusieurs valeurs différentes), cela peut devenir fastidieux et sujet aux erreurs à maintenir, et la conception a toujours l’inconvénient que vous devrez modifier cette méthode de construction si jamais vous ajoutez une nouvelle sous-classe ou modifiez la sous-classe à utiliser selon quelle entrée.
Heureusement, il existe une méthode beaucoup plus élégante, mais malheureusement aussi beaucoup moins connue, de procéder, à savoir l’utilisation du cadre SysExtension.
Ce cadre profite des attributs que vous pouvez utiliser pour décorer vos sous-classes afin de permettre au système de déterminer quelle sous-classe doit être utilisée pour gérer quoi. Vous aurez toujours besoin d’une méthode construct, mais si elle est bien faite, vous n’aurez jamais à la modifier lors de l’ajout de nouvelles sous-classes.
Prenons un exemple imaginaire et disons que vous allez implémenter une hiérarchie qui effectue un traitement basé sur la table InventTrans. Le traitement à effectuer dépend du StatusReceipt et du StatusIssue des enregistrements, ainsi que du fait que les dossiers soient liés à SalesLine, PurchLine ou à aucun des deux. Déjà, tu regardes beaucoup de combinaisons différentes.
Disons alors que vous savez que pour l’instant vous n’avez besoin que de manipuler quelques combinaisons, mais que vous savez aussi qu’on vous demandera de pouvoir gérer de plus en plus de combinaisons au fil du temps.
Soyons assez simples et disons que pour l’instant vous n’avez à gérer que les dossiers liés à SalesLine avec un StatusIssue de ReservPhysical ou ReservOrdered, toutes les autres combinaisons peuvent être ignorées pour l’instant, mais comme vous savez que vous devrez les gérer plus tard, vous voudrez concevoir votre code de façon à le rendre facilement extensible.
Votre hiérarchie pourrait ressembler à ceci pour l’instant :
- MyProcessorMyProcessor_SalesMyProcessor_Sales_ReservOrderedMyProcessor_Sales_ReservPhysical
Maintenant, vous pourriez facilement implémenter une méthode dans la super classe qui instancie une sous-classe basée sur un enum ModuleInventPurchSales et un enum StatusIssue. Mais il faudra alors modifier la superclasse chaque fois que vous ajoutez une sous-classe, et ce n’est pas vraiment l’idée de l’héritage en programmation orientée objet. Après tout, vous n’avez pas besoin de modifier RunBaseBatch ou SysOperationServiceBase à chaque fois que vous ajoutez un nouveau travail batch.
À la place, vous pouvez utiliser le cadre SysExtension. Cela vous obligera à ajouter une autre classe, qui doit étendre SysAttribute. Cette classe sera utilisée comme attribut avec lequel vous pourrez décorer vos cours de traitement.
Cette classe est très similaire à la façon dont on créerait une classe de contrat de données pour une implémentation SysOperation, en ce sens qu’elle comporte certains membres de données et des méthodes parm pour obtenir et définir ces valeurs.
Dans notre cas, la ClassDeclaration pourrait ressembler à ceci :
{
ModuleInventPurchSales module;
StatusIssue statusIssue;
StatusReceipt statusReceipt
}
Vous devez créer une nouvelle méthode pour instancier tous les membres de données. Si tu veux, tu peux donner certaines ou toutes les valeurs par défaut, mais je ne l’ai pas fait.
StatusIssue _statusIssue,
StatusReceipt _statusReceipt)
{
;
super();
module = _module;
statusIssue = _statusIssue;
statusReceipt = _statusReceipt;
}
Et vous devriez aussi implémenter une méthode parm pour chaque membre de données, mais je les ai omises ici car je suis sûr que vous savez comment faire – sinon, considérons ça comme un exercice;-)
Maintenant, vous pouvez utiliser votre classe d’attribut pour décorer chacune de vos classes de traitement. Par exemple, les déclarations de classe pourraient ressembler à ceci :
StatusIssue::None,
StatusReceipt::None)]
class MyProcessor_Sales extends MyProcessor
{
}
[MyProcessorSystemAttribute(ModuleInventPurchSales::Sales,
StatusIssue::ReservOrdered,
StatusReceipt::None)]
class MyProcessor_Sales_ReservOrdered extends MyProcessor_Sales
{
}
[MyProcessorSystemAttribute(ModuleInventPurchSales::Sales,
StatusIssue::ReservPhysical,
StatusReceipt::None)]
class MyProcessor_Sales_ReservPhysical extends MyProcessor_Sales
{
}
Vous pouvez bien sûr nommer vos classes comme vous le souhaitez, l’important ici est de décorer vos classes avec des attributs correspondant au type de traitement qu’elles effectuent. (Mais gardez en tête qu’il existe des conventions de nommage pour les hiérarchies de classes dans Dynamics AX et c’est toujours une bonne idée de les suivre, si possible).
Maintenant que vous avez décoré vos classes pour identifier le type de traitement que chacune effectue, vous pouvez profiter du cadre SysExtension pour instancier les objets des sous-classes au besoin.
Dans votre super classe (MyProcessor), vous pourriez ajouter une méthode de construction comme ceci :
StatusIssue _statusIssue,
StatusReceipt _statusReceipt)
{
MyProcessor ret;
MyProcessorSystemAttribute attribute;
;
attribute = new MyProcessorSystemAttribute( _module,
_statusIssue,
_statusReceipt);
ret = SysExtensionAppClassFactory::getClassFromSysAttribute(classStr(MyProcessor), attribute);
if (!ret)
{
// no class found
// here you could throw an error, instantiate a default
// processor instead, or just do nothing, up to you
}
return ret;
}
La partie vraiment intéressante – et en fait l’objet (pardonnez le jeu de mots) de tout ce message – c’est la méthode getClassFromSysAttribute() dans la classe SysExtensionAppClassFactory. Ce que fait cette méthode, c’est qu’elle accepte le nom de la superclasse d’une hiérarchie (et cette superclasse n’a pas besoin d’être en haut de la hiérarchie; cela signifie simplement que seules les classes étendant cette classe seront admissibles) et un objet attribut.
Il retourne ensuite un objet d’une classe qui étend la superclasse spécifiée et est décoré d’un attribut correspondant.
Vous pouvez évidemment ajouter autant de validation ou de logique supplémentaire à la méthode construct que vous le souhaitez, mais l’important à retenir ici est qu’une fois implémentée, vous ne devriez plus jamais avoir à modifier cette méthode. Tu peux ajouter des sous-classes à la hiérarchie et tant que tu t’assures de les décorer correctement, la méthode des constructions les trouvera même si elles n’existaient pas au moment de l’écriture.
Qu’en est-il de la performance? Honnêtement, je n’ai pas essayé de le comparer, mais mon intuition me dit que ça performe probablement moins bien que le design classique à déclaration de switch. Cependant, étant donné que de loin les plus grands problèmes de performance dans Dynamics AX sont causés par l’accès à la base de données, je ne m’en ferais pas trop.
Bien sûr, si vous implémentez quelque chose qui nécessitera la création rapide de milliers d’objets, vous voudrez peut-être approfondir, mais dans les cas classiques où vous n’instantiez qu’un seul objet pour un traitement long, je doute que cela ait de l’importance. Aussi, en considérant mon conseil de dépannage (paragraphe suivant), il semble que le framework SysExtension repose sur la mise en cache, donc dans un système en cours d’exécution, je doute que cela ait un impact significatif sur les performances.
Dépannage : Si la méthode construct ne trouve pas vos sous-classes même si vous êtes certain qu’elles sont correctement décorées, cela peut être un problème de mise en cache. Essaie de vider les caches sur le client et le serveur. Il ne devrait pas être nécessaire de redémarrer réellement l’AOS, mais ça pourrait être le dernier recours.
Lectures complémentaires
Si vous avez apprécié cet article, vous aimerez peut-être aussi ces suggestions :
- Aperçu rapide de Dynamics AX 2012 SysOperation Framework
- Erreur « Aucune classe de métadonnées définie pour l’objet contrat de données » dans Dynamics AX 2012
- Appel des services de documents AIF directement depuis X++ dans Dynamics AX 2012
