grails foreign-keys gorm has-one

grails hasOne vs variable miembro directo



foreign-keys gorm (4)

Digamos que tengo una clase de dominio Grails que se parece a

class Person { Address address }

También podría declararlo como

class Person { static hasOne = [address:Address] }

La segunda forma movería la clave externa a la tabla de direcciones en lugar de a la tabla de personas.

¿Cuáles son los beneficios (o desventajas) prácticos de hacer esto de una manera frente a la otra? Por lo que yo entiendo, ambos usarán claves externas, es solo una cuestión de dónde vive la clave externa.


Si la clave externa existe en la tabla de direcciones, entonces esa dirección solo puede tener una persona. Si la clave externa está en la tabla de personas, varias personas pueden tener la misma dirección.

No se trata de qué manera es mejor / peor. Se trata de cuál es la forma correcta de modelar sus datos.


Creo que el uso de hasOne en Grails es particularmente confuso. Por ejemplo, esta pregunta pregunta qué sucede cuando una relación toOne se declara de la siguiente manera:

class Person { static hasOne = [address: Address] }

Como se indicó anteriormente, esto hace que la clave externa person_id aparezca en la tabla de direcciones, lo que significa que cada dirección solo puede señalar a una persona. Lo que me parece extraño, entonces, es que a pesar de que el código está escrito como "una persona tiene una dirección", el resultado real es que "una dirección tiene una persona".

Y, de hecho, definido únicamente como arriba, no hay nada (en el nivel de la base de datos) que impida que más de un registro de Dirección apunte a la misma Persona, lo que significa que una Persona realmente no necesita tener una Dirección después de todo.

Curiosamente, obtendrá la misma representación de la base de datos si creó la clase Address de esta manera:

class Address { Person person }

La clave externa person_id estará en la tabla de direcciones, igual que en el ejemplo anterior, pero obviamente, no se puede obtener de la persona a la dirección en el código sin definir esa relación de alguna manera también.

También es interesante que, si estuvieras modelando una relación entre muchas personas en la base de datos, usarías el mismo diseño de tabla. Colocaría la clave principal del padre (person_id) en la tabla secundaria. Desde la perspectiva de una base de datos, el uso de hasOne crea la misma estructura que crearía una relación aMucha.

Por supuesto, no solo estamos creando tablas de bases de datos, estamos creando clases de dominio Grails que tienen algún comportamiento asociado a ellas, y algo de cumplimiento de la semántica de relaciones. En este ejemplo empresarial particular, probablemente no desee compartir el mismo registro de Dirección con varias Personas, solo desea almacenar la Dirección por separado (tal vez preparándose para el día en que una Persona tenga varias Direcciones). Probablemente votaría por este enfoque:

class Person { Address address static constraints = { address unique:true } }

La clave externa address_id estará en la tabla Person, y la restricción única address_id que no haya dos registros Person apuntando a la misma dirección.


Sugiero lo siguiente ...

class Person { ... static hasOne = [address: Address] } class Address { ... static belongsTo = [person: Person] }

Una persona tiene una dirección y la dirección pertenece a una persona.

De esta forma, cuando eliminas a una persona, la dirección también se eliminará, sin problemas.

Creo que esta es la mejor manera de hacer esto.


La dirección " HasOne " de la persona y la dirección " pertenece a " la persona .

Tener la clave externa en la tabla "hijo" tiene más sentido porque de esta manera el niño se rompería si el padre falta. Una persona puede existir sin su dirección, pero la "dirección de una persona" sin una persona no tiene sentido. Entonces, la Dirección debe ser el lado más débil de la relación.

Al hacerlo de esta manera en griales, ambas entidades tendrán la referencia entre sí, por lo que no se sentirá extraño. Además, el comportamiento en cascada predeterminado guardará y eliminará la Dirección cuando guarde la Persona, pero si desea eliminarla, la Persona permanecerá guardada.