DSL Factory

La communauté francophone autour des DSL Tools, et de l'extensibilité Visual Studio
The French-speaking community about DSL Tools and Visual Studio Extensibility
Bienvenue à DSL Factory Identification | Inscription | Aide
dans
Accueil Blogs Forums Photos Fichiers Roller

Dérivation des relations

Dernier message 08-24-2007, 2:36 par Heinzer.David. 2 réponses.
Trier les messages Précédent
  • Dérivation des relations

     08-08-2007, 3:32

    Bonjour à tous,
    Je rencontre une nouvelle difficulté pour modéliser ce que je souhaite... Et le livre sur les DSL n'aborde que très succintement mon problème (p.126 à 128, "More on Relationship derivation").
    Grossièrement, j'aimerai pouvoir spécialiser mes relations entre concepts. Un exemple sera surement plus parlant...

    Imaginons que je modélise deux concepts génériques GenericClass et GenericAttribute. Je place une embedded relation GenericClassHasGenericAttributes entre les deux. GenericClass possède 0..* GenericAttributes dans la propriété nommée Attributes; GenericAttribute ne peut avoir que 0..1 GenericClass dans la propriété Class.

    Maintenant, je crée deux nouveaux concepts : Class qui hérite de GenericClass et Attribute qui hérite de GenericAttribute. Je veux pouvoir spécifier que ces concepts ont des contraintes supplémentaires dans leurs relations, ici, un concept Class ne peut être relié qu'à un concept Attribute.

    Ce que je veux à tout pris garder, c'est au final n'avoir qu'une seule et même propriété pour l'ensemble des cas possibles : la propriété Attributes dans le concept Class et la propriété Class dans le concept Attribute. Leur contenu pouvant donc varier suivant le type des concepts mis en jeux.

    Comment pourrais-je mettre en place cette contrainte dans les DSL?

    ---
    J'ai actuellement une solution lors de l'utilisation d'une "reference relationship". Je vous la donne car :
    1: Ce n'est peut être pas la meilleure méthode et dans ce cas, cela me permettra de lire vos remarques
    2: Ca peut intéresser certaines personnes.

    J'ai gardé l'exemple décrit plus haut, en remplaçant la relation "embedded" par une relation "reference".
    Ensuite, j'ai modifié le "Connection Builders" accessible à partir du Dsl Explorer.
    - Pour commencer, j'ai supprimer le ClassReferencesAttributesBuilder. En effet, comme je vais le redéfinir plus tard, je n'en ai plus besoin.
    - Ensuite, je rajoute dans le GenericClassReferencesGenericAttributesBuilder un nouveau "Link Connect Directive" par clique droit.
    Je sélectionne ce nouvel item pour l'éditer dans la fenêtre "DSL Details". J'indique dans le menu déroulant la relation ClassReferencesAttributes. Puis, j'indique la source et la cible de cette relation : source = Class et target = Attribute.
    - Grâce à ça, on peut contraindre maintenant pour une même connectionbuilder plusieurs comportements/contraintes suivant la source et/ou la cible de la relation.
    J'ai maintenant deux items dans mon builder : GenericClassReferencesGenericAttributes et ClassReferencesAttributes. Je dois, pour obtenir le comportement souhaité, limiter la relation GenericClassReferencesGenericAttributes car celle-ci permet de base à n'importe quelle GenericClass (et ses classes dérivées telle que Class!) de se relier à n'importe quelle GenericAttribute (et donc Attribute!). L'objectif est ici de contraindre une relation de type GenericClass <--> GenericAttribute OU Class <--> Attribute. La seconde relation ayant déjà été décrite dans l'item ClassReferencesAttributes, il nous reste à définir la première.
    Pour cela, j'ai selectionné l'item GenericClassReferencesGenericAttributes et accédé à ses propriétés par la fenêtre "DSL Details".
    J'ai coché la case "Custom accept" de la ligne GenericClass dans l'onglet "Source role directives". Je dois alors déclarer mes propres fonctions dans la classe partielle GenericClassReferencesGenericAttributesBuilder :
    partial class GenericClassReferencesGenericAttributesBuilder
    {
       private static bool CanAcceptGenericClassAsSource(GenericClass  genericClass)
       {
          if (genericClass is Class)
             return false;
          return true;
       }
       private static bool CanAcceptGenericClassAndGenericAttributeAsSourceAndTarget(GenericClass genericClass, GenericAttribute genericAttribute)
       {
          if (genericClass is Class || genericAttribute is Attribute)
             return false;
          return true;
       }
    }
    Au niveau modeleur, l'utilisateur ne peut maintenant relier que des GenericClass à des GenericAttribute et des Class à des Attribute. Et cela, sans utiliser plusieurs champs (Attributes dans GenericClass et dérivés ; Class dans GenericAttribute et dérivés) pour chacune de ces relations.
    Ce qui me gène aujourd'*** dans cette solution est de devoir faire appel à du CustomCode... En gros, si le métamodèle change, il y'a de forte chance pour que je sois obligé de devoir modifier mon code pour l'adapter. J'aurai aimé une solution plus générique et automatique.
    Je pourrai fournir ce projet correspondant dans la section appropriée du site.

  • Re:Dérivation des relations

     08-21-2007, 3:53

    Bonjour David,

    Je reviens juste de vacances d'où ma réponse tardive.

    Pour répondre à ton problème et pour éviter de créer du "custom code", il te faut utiliser la notion nommées "Element merge directive". Cette directive permet de déclarer au niveau de chaque élément le type d'élément qui peuvent être "droppés" sur un autre.

    Dans ton cas, il te faut déclarer au niveau de ta classe "Class" qu'elle ne supporte que des merges avec une classe "Attribute". N'oublie pas de supprimer les merges de ta classe "GenericClass" sinon le test sera toujours vrai.

    Tu peux supprimer ton code, enlver l'option "custom accept", regénérer et cela devrait marcher correctement.

    Petite remarque sur ton exemple qui est tout à fait correct (et qui permet de faire des séléctions plus complexes que la simple vérification du type), il n'était pas nécessaire de supprimer le ClassReferencesAttributesBuilder, il suffisait juste de le repersonnaliser.

     

     

     


    Alain Metge
  • Re:Dérivation des relations

     08-24-2007, 2:36

    Merci de ta réponse Alain!
    Je viens de regarder du coté de la fonctionnalité "Element merge directive". Mais je n'arrive pas à obtenir ce que je souhaite. :(

    Dans ton explication, tu dis
    Dans ton cas, il te faut déclarer au niveau de ta classe "Class" qu'elle ne supporte que des merges avec une classe "Attribute". N'oublie pas de supprimer les merges de ta classe "GenericClass" sinon le test sera toujours vrai.

    En effet, dans ce cas, pas de soucis. Mais je ne veux pas supprimer le merge dans "GenericClass", sinon je ne pourrais pas ajouter de GenericProperty dans ce concept!
    Il y a une option pouvant être désactivée dans les merges directives qui me semblait fournir une solution  : "Applies to subclasses". J'ai décoché cette option dans le merge au niveau de mon concept GenericClass, espérant ainsi que le merge ne s'applique pas sur mon concept Class. Mais ça ne change rien du tout...

    Quand je crée une forme représentant mon type "Class" dans le modeleur, et que je fais clique-droit dessus, j'ai toujours le choix entre "Create a GenericProperty item" et "Create a Property item". A noter que j'ai un message d'erreur si je sélectionne "Create a GenericProperty item".

    J'ai bien l'impression d'être obligé de passer par du custom code... :(

Voir comme un flux RSS en XML
Propulsé par Community Server, par Telligent Systems