Loading...
X

Grails partie 4 : Les relations

Grails_logo

 

Dans ce quatrième article sur le framework Grails, nous allons aborder les relations entre entités. Cela va nous permettre de posséder enfin un modèle de données correct et permettre à l’utilisateur, dans notre cas par exemple, de choisir à quelle course il veut participer.

Nous partons du principe que vous avez déjà suivi les trois articles précédents : Introduction à GrailsGrails partie 2 : création d’une application basique et Grails partie 3 : La validation.

Nous allons voir quatre types de relations puis les mettre en oeuvre sur notre application que nous mettons à jour depuis le deuxième article. Pour rendre notre explication plus claire, nous l’agrémenterons d’exemples très parlants de la documentation officielle.

Relation many-to-one

 

Commençons par la relation la plus simple. Une relation many-to-one n’est rien de plus qu’une classe possédant un attribut du type d’une autre classe. Voici comment ceci est réalisé dans une application Grails :

class Face {
    Nose nose
}
class Nose {
}

Rien de bien compliqué ici, cette relation est réalisée de la même façon que dans beaucoup de langages.
Si nous voulons ensuite rendre cette relation bidirectionnelle et ainsi activer la sauvegarde et la suppression en cascade, il nous suffit de rajouter un attribut à la classe Nose :

class Nose {
    static belongsTo = [face:Face]
}

Nous spécifions ainsi que la classe Nose appartient à la classe Face. Si nous supprimons un objet Face de la base de données, son objet Nose associé sera également supprimé. Vous pouvez remarquer que la façon de déclarer cet attribut est un peu spéciale. Nous devons spécifier le nom de l’attribut suivi de son type.

 

Relation one-to-one

 

La relation one-to-one ne diffère pas beaucoup de la précédente. Nous devons utiliser la propriété hasOne du côté de la classe propriétaire.

class Face {
    static hasOne = [nose:Nose]
}
class Nose {
    Face face
}

Ici, il s’agit bien de la figure qui possède un nez et non l’inverse.

 

Relation one-to-many

 

La relation one-to-many est également très simple à mettre en place :

class Author {
    static hasMany = [books: Book]
}
class Book {
}

Il suffit, comme vous pouvez le voir, de déclarer un attribut hasMany du côté approprié de la relation. Ici, un auteur possède plusieurs livres. Cette collection books sera automatiquement injectée par Grails et sera de type java.util.Set. Elle sera chargée de façon lazy. Si vous souhaitez rendre cette relation bidirectionnelle, il suffit de faire la même opération que précédemment :

class Book {
    static belongsTo = [author: Author]
}

Relation many-to-many

 

Pour cette dernière relation, many-to-many, chaque objet possède plusieurs autres objets d’un même type. Il suffit donc de déclarer un attribut hasMany des deux côtés de la relation. En plus de ceci, vous devrez définir un belongsTo du côté de la classe non propriétaire :

class Book {
    static belongsTo = Author
    static hasMany = [authors:Author]
}
class Author {
    static hasMany = [books:Book]
}

Ainsi, la classe Author devient « propriétaire », et si elle est supprimée, tous ses Books associés le seront également. Vous devriez cependant éviter de vous servir de cette relation, car la génération des vues et contrôleurs de Grails ne la prend pas charge. Si vous vous en servez, vous devrez donc la gérer vous-même.

 

Mise en application

 

Maintenant que nous avons passé en revue les différents types de relations pouvant exister, nous allons les mettre en place sur notre application RaceTrack. Reprenons notre modèle de données :

RaceTrack

 

D’après notre schéma, nous allons ici nous retrouver avec deux relations one-to-many. Une course peut avoir plus enregistrements et un participant peut participer à plusieurs courses (et donc avoir plusieurs enregistrements). Voici le résultat de la mise en place de ces deux relations :

class Race {

    String name
    Date startDate
    String city
    BigDecimal distance
    BigDecimal cost
    Integer maxRunners

    static hasMany = [registrations:Registration]

    static constraints = {
        name blank: false, maxSize: 40
        startDate validator: {return(it > newDate())}
        city inList:["Paris", "Marseille"]
        distance min: 0.0
        cost min: 0.0, max: 100.0
        maxRunners min: 0, max: 1000
        registrations()
    }
}
class Registration {

    Boolean paid
    Date dateCreated

    static belongsTo = [race:Race, runner:Runner]

    static constraints = {
        paid()
        dateCreated()
        race()
        runner()
    }
}
class Runner {

    String firstName
    String lastName
    Date dateOfBirth
    String gender
    String address
    String city
    String zipcode
    String email

    static hasMany = [registrations:Registration]

    static constraints = {
        firstName blank:false, maxSize: 40
        lastName blank:false, maxSize: 40
        dateOfBirth validator: {return (it < new Date())}
        gender inList:["Homme", "Femme"]
        address maxSize: 100
        city maxSize: 60
        zipcode()
        email email:true, unique: true
        registrations()
    }
}

Il ne vous reste plus qu’à regénérer les vues et contrôleurs pour ces trois classes, comme vu dans le deuxième article.

Vous pouvez maintenant lancer l’application, créer une Race, un Runner, puis les relier grâce à une Registration.

Création relation registration

Il ne nous reste plus qu’un petit détail à régler, l’affichage des objets. Comme vous pouvez le voir, le label par défaut est le nom de la classe, suivi de son id. Pour changer ceci, il vous suffit de surcharger la méthode toString, tout comme en Java.

class Race {

    [...]

    String toString(){
        "${name}, ${startDate?.format('dd/MM/yyyy')}"
    }
}
class Runner {

    [...]

    String toString(){
        "${lastName} ${firstName}"
    }
}

Retournez sur la création d'une Registration et voici le résultat !

Création relation registration 2

 

Ainsi, nous avons fait le tour dans cet article des différentes relations possibles et mis à jour notre application en conséquence. Vous avez pu voir que le tout reste très simple, rapide et intuitif à implémenter.

Pour le prochain article, nous aborderons et analyserons plus en détail les contrôleurs et les vues.

 

Sources

http://www.infoq.com/minibooks/grails-getting-started

http://grails.org/doc/latest/