(Quick Reference)

5.2.1 Asociación en GORM - Reference Documentation

Authors: Graeme Rocher, Peter Ledbrook, Marc Palmer, Jeff Brown, Luke Daley, Burt Beckwith

Version: null

5.2.1 Asociación en GORM

Relationships define how domain classes interact with each other. Unless specified explicitly at both ends, a relationship exists only in the direction it is defined.
Las relaciones definen cómo interactúan entre sí las clases de dominio. A menos que de forma explícita se especifique en ambos lados, una relación existe solo en la dirección que es definida.

5.2.1.1 Varios-a-uno y uno-a-uno

A many-to-one relationship is the simplest kind, and is defined with a property of the type of another domain class. Consider this example:
Una relación de varios-a-uno es el tipo más simple, se define mediante una propiedad del tipo de otra clase de dominio. Considere este ejemplo:

Example A
Ejemplo A

class Face {
    Nose nose
}

class Nose {
}

In this case we have a unidirectional many-to-one relationship from Face to Nose. To make this relationship bidirectional define the other side as follows:
En este caso tenemos una relación unidireccional varios-a-uno desde Face hacia Nose. Para hacer esta relación bidireccional, es necesario definir el otro lado de la siguiente manera:

Example B
Ejemplo B

class Face {
    Nose nose
}

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

In this case we use the belongsTo setting to say that Nose "belongs to" Face. The result of this is that we can create a Face, attach a Nose instance to it and when we save or delete the Face instance, GORM will save or delete the Nose. In other words, saves and deletes will cascade from Face to the associated Nose:
En este caso establecemos mediante belongsTo que Nose pertenece a Face. Como resultado de esto podemos crear Face, agregar una instancia de Nose y cuando guardemos o eliminemos la instancia de Face, GORM guardara o eliminara Nose. En otras palabras, la actualización y eliminación se realizaran en cascada desde Face hacia Nose.

new Face(nose:new Nose()).save()

The example above will save both face and nose. Note that the inverse is not true and will result in an error due to a transient Face:
En el ejemplo anterior ambos, face y nose serán guardados. Esto no funcionara de modo inverso y el resultado seria un error debido a un Face que es transitorio.

new Nose(face:new Face()).save() // will cause an error
new Nose(face:new Face()).save() // Esto causara un error

Now if we delete the Face instance, the Nose will go too:
Si borramos la instancia Face, Nose también sera eliminada:

def f = Face.get(1)
f.delete() // both Face and Nose deleted
def f = Face.get(1)
f.delete() // Ambos Face y Nose serán eliminados

To make the relationship a true one-to-one, use the hasOne property on the owning side, e.g. Face:
Para hacer que la relación sea verdaderamente uno-a-uno, utilice la propiedad hasOne en el lado que define la posesión, por ejemplo, Face:

Example C
Ejemplo C

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

class Nose {
    Face face
}

Note that using this property puts the foreign key on the inverse table to the previous example, so in this case the foreign key column is stored in the nose table inside a column called face_id. Also, hasOne only works with bidirectional relationships.
Tenga en cuenta que al hacer uso de esta propiedad, la clave externa sera colocada en la tabla opuesta al ejemplo anterior, por lo que en este caso la columna de clave externa se almacena en la tabla nose en una columna llamada face_id. Además, hasOne sólo funciona en las relaciones bidireccionales.

Finally, it's a good idea to add a unique constraint on one side of the one-to-one relationship:
Por último, es conveniente añadir una restricción de unicidad en un lado de la relación uno-a-uno:

class Face {
    static hasOne = [nose:Nose]

static constraints = { nose unique: true } }

class Nose {
    Face face
}

5.2.1.2 Uno-a-varios

A one-to-many relationship is when one class, example Author, has many instances of a another class, example Book. With Grails you define such a relationship with the hasMany setting:
Una relación uno-a-varios es cuando una clase, por ejemplo Author, tiene varias instancias de otra clase, por ejemplo Book. En Grails se establece este tipo de relación utilizando hasMany:

class Author {
    static hasMany = [books: Book]

String name }

class Book {
    String title
}

In this case we have a unidirectional one-to-many. Grails will, by default, map this kind of relationship with a join table.
En este caso tenemos una relación unidireccional uno-a-varios. De manera predeterminada, Grails mapeara este tipo de relación mediante una tabla de unión.

The ORM DSL allows mapping unidirectional relationships using a foreign key association instead
El DSL ORM permite mapear relaciones unidireccionales mediante el uso de una clave externa.

Grails will automatically inject a property of type java.util.Set into the domain class based on the hasMany setting. This can be used to iterate over the collection:
Grails inyectara automáticamente una propiedad de tipo java.util.Set en la clase de dominio basándose en hasMany. Esta propiedad puede ser usada para iterar sobre la colección:

def a = Author.get(1)

for (book in a.books) { println book.title }

The default fetch strategy used by Grails is "lazy", which means that the collection will be lazily initialized on first access. This can lead to the n+1 problem if you are not careful.
De manera predeterminada Grails utilizara una estrategia de recuperación "lazy", lo que significa que la colección sera inicializada hasta que se accede por primera vez. Esto puede provocar que se incurra en el problema n+1 si usted no es cuidadoso.

If you need "eager" fetching you can use the ORM DSL or specify eager fetching as part of a query
Si necesita recuperación "eager" puede utilizar el DSL ORM o puede especificar la recuperación "eager" como parte de una consulta

The default cascading behaviour is to cascade saves and updates, but not deletes unless a belongsTo is also specified:
El comportamiento predeterminado de la cascada es guardar y actualizar, pero no eliminar a menos que también se especifique belongsTo:

class Author {
    static hasMany = [books: Book]

String name }

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

If you have two properties of the same type on the many side of a one-to-many you have to use mappedBy to specify which the collection is mapped:
Si usted tiene dos propiedades del mismo tipo en el lado varios de uno-a-varios, deberá utilizar mappedBy para especificar la colección a mapear:

class Airport {
    static hasMany = [flights: Flight]
    static mappedBy = [flights: "departureAirport"]
}

class Flight {
    Airport departureAirport
    Airport destinationAirport
}

This is also true if you have multiple collections that map to different properties on the many side:
Esto también sera válido si tiene varias colecciones que mapean a diferentes propiedades en el lado varios:

class Airport {
    static hasMany = [outboundFlights: Flight, inboundFlights: Flight]
    static mappedBy = [outboundFlights: "departureAirport",
                       inboundFlights: "destinationAirport"]
}

class Flight {
    Airport departureAirport
    Airport destinationAirport
}

5.2.1.3 Varios-a-varios

Grails supports many-to-many relationships by defining a hasMany on both sides of the relationship and having a belongsTo on the owned side of the relationship:
Grails tiene soporte para relaciones varios-a-varios mediante la inclusión de hasMany en ambos lados de la relación y del lado que expresa ser la propiedad se incluye belongsTo:

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

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

Grails maps a many-to-many using a join table at the database level. The owning side of the relationship, in this case Author, takes responsibility for persisting the relationship and is the only side that can cascade saves across.
A nivel de la base de datos Grails mapea una relación varios-a-varios mediante una tabla de unión. El lado propietario de la relación, en este caso Author, asume la responsabilidad de la persistencia de la relación y es el único que puede propagar la actualización.

For example this will work and cascade saves:
Por ejemplo, esto propagaría la creación de manera correcta:

new Author(name:"Stephen King")
        .addToBooks(new Book(title:"The Stand"))
        .addToBooks(new Book(title:"The Shining"))
        .save()

However this will only save the Book and not the authors!
Sin embargo, esto sólo guardaría a Book y no a los autores!

new Book(name:"Groovy in Action")
        .addToAuthors(new Author(name:"Dierk Koenig"))
        .addToAuthors(new Author(name:"Guillaume Laforge"))
        .save()

This is the expected behaviour as, just like Hibernate, only one side of a many-to-many can take responsibility for managing the relationship.
Este es el comportamiento esperado, al igual que en Hibernate, sólo un lado de la relación varios-a-varios puede asumir la responsabilidad de la gestión.

Grails' Scaffolding feature does not currently support many-to-many relationship and hence you must write the code to manage the relationship yourself
Actualmente el Scaffolding de Grails no es compatible con relaciones del tipo varios-a-varios, y por lo tanto, usted deberá escribir el código para manejar este tipo de relación.

5.2.1.4 Colecciones de tipos básicos

As well as associations between different domain classes, GORM also supports mapping of basic collection types. For example, the following class creates a nicknames association that is a Set of String instances:
Al igual que con las asociaciones entre diferentes tipos de clases de dominio, GORM también es compatible con el mapeo de colecciones de tipos básicos. Por ejemplo, la clase siguiente, crea una asociación de nicknames que es un Set de instancias String:

class Person {
    static hasMany = [nicknames: String]
}

GORM will map an association like the above using a join table. You can alter various aspects of how the join table is mapped using the joinTable argument:
GORM mapeara esta asociación utilizando una tabla de unión. Usted puede modificar varios aspectos del mapeo de la tabla de unión mediante el argumento joinTable:

class Person {

static hasMany = [nicknames: String]

static mapping = { hasMany joinTable: [name: 'bunch_o_nicknames', key: 'person_id', column: 'nickname', type: "text"] } }

The example above will map to a table that looks like the following:
Al ejemplo anterior corresponderá una tabla como la siguiente:

bunch_o_nicknames Table
Tabla bunch_o_nicknames
---------------------------------------------
| person_id         |     nickname          |
---------------------------------------------
|   1               |      Fred             |
---------------------------------------------