Dans la section exemple de la @OneToMany
référence d'annotation JPA :
Exemple 1-59 @OneToMany - Classe client avec génériques
@Entity
public class Customer implements Serializable {
...
@OneToMany(cascade=ALL, mappedBy="customer")
public Set<Order> getOrders() {
return orders;
}
...
}
Exemple 1-60 @ManyToOne - Classe de commande avec génériques
@Entity
public class Order implements Serializable {
...
@ManyToOne
@JoinColumn(name="CUST_ID", nullable=false)
public Customer getCustomer() {
return customer;
}
...
}
Il me semble que l' Customer
entité est propriétaire de l'association. Cependant, dans l'explication de l' mappedBy
attribut dans le même document, il est écrit que:
si la relation est bidirectionnelle, définissez l'élément mappedBy du côté inverse (non propriétaire) de l'association sur le nom du champ ou de la propriété qui possède la relation, comme le montre l'exemple 1-60.
Cependant, si je ne me trompe pas, il semble que dans l'exemple, le mappedBy
est en fait spécifié du côté propriétaire de l'association, plutôt que du côté non propriétaire.
Ma question est donc essentiellement:
Dans une association bidirectionnelle (un à plusieurs / plusieurs à un), laquelle des entités est le propriétaire? Comment pouvons-nous désigner le côté Un comme propriétaire? Comment désigner le côté Many comme propriétaire?
Qu'entend-on par «le côté inverse de l'association»? Comment pouvons-nous désigner le côté Un comme l'inverse? Comment pouvons-nous désigner le côté Multiple comme l'inverse?
Réponses:
Pour comprendre cela, vous devez prendre du recul. En OO, le client est propriétaire des commandes (les commandes sont une liste dans l'objet client). Il ne peut pas y avoir de commande sans client. Le client semble donc être le propriétaire des commandes.
Mais dans le monde SQL, un élément contiendra en fait un pointeur vers l'autre. Puisqu'il y a 1 client pour N commandes, chaque commande contient une clé étrangère du client auquel elle appartient. C'est la "connexion" et cela signifie que l'ordre "possède" (ou contient littéralement) la connexion (l'information). C'est exactement le contraire du monde OO / modèle.
Cela peut aider à comprendre:
Le côté inverse est le "propriétaire" OO de l'objet, dans ce cas le client. Le client n'a pas de colonnes dans la table pour stocker les commandes, vous devez donc lui indiquer où dans la table des commandes il peut enregistrer ces données (ce qui se passe via
mappedBy
).Un autre exemple courant est celui des arbres avec des nœuds qui peuvent être à la fois parents et enfants. Dans ce cas, les deux champs sont utilisés dans une classe:
Ceci explique les travaux de conception plusieurs-à-un de "clé étrangère". Il existe une deuxième approche qui utilise une autre table pour maintenir les relations. Cela signifie que pour notre premier exemple, vous avez trois tables: celle avec les clients, celle avec les commandes et une table à deux colonnes avec des paires de clés primaires (customerPK, orderPK).
Cette approche est plus flexible que celle ci-dessus (elle peut facilement gérer un-à-un, plusieurs-à-un, un-à-plusieurs et même plusieurs-à-plusieurs). Le prix est que
C'est pourquoi je recommande rarement cette approche.
la source
@Parent
ou@Child
au lieu de "XtoY" pour indiquer ce que signifie la connexion (plutôt que comment elle est implémentée )Incroyablement, en 3 ans, personne n'a répondu à votre excellente question avec des exemples des deux façons de cartographier la relation.
Comme mentionné par d'autres, le côté «propriétaire» contient le pointeur (clé étrangère) dans la base de données. Vous pouvez désigner l'un ou l'autre des côtés comme propriétaire, cependant, si vous désignez le côté Un comme propriétaire, la relation ne sera pas bidirectionnelle (le côté inverse aka «plusieurs» n'aura aucune connaissance de son «propriétaire»). Cela peut être souhaitable pour l'encapsulation / couplage lâche:
La seule solution de mappage bidirectionnel est que le côté "plusieurs" possède son pointeur vers le "un" et utilise l'attribut @OneToMany "mappedBy". Sans l'attribut "mappedBy", Hibernate s'attend à un double mappage (la base de données aurait à la fois la colonne de jointure et la table de jointure, ce qui est redondant (généralement indésirable)).
la source
L'entité qui a la table avec la clé étrangère dans la base de données est l'entité propriétaire et l'autre table, pointée, est l'entité inverse.
la source
Règles simples des relations bidirectionnelles:
Pour les relations bidirectionnelles plusieurs à un, le côté plusieurs est toujours le côté propriétaire de la relation. Exemple: 1 pièce a plusieurs personnes (une personne appartient à une seule pièce) -> le côté propriétaire est Personne
Pour les relations bidirectionnelles un à un, le côté propriétaire correspond au côté qui contient la clé étrangère correspondante.
Pour les relations bidirectionnelles plusieurs à plusieurs, chaque côté peut être le côté propriétaire.
L'espoir peut vous aider.
la source
Pour deux classes d'entités Customer et Order, hibernate créera deux tables.
Cas possibles:
mappedBy n'est pas utilisé dans la classe Customer.java et Order.java alors->
Côté client, une nouvelle table sera créée [nom = CUSTOMER_ORDER] qui conservera le mappage de CUSTOMER_ID et ORDER_ID. Ce sont les clés primaires des tables client et commande. Du côté de la commande, une colonne supplémentaire est requise pour enregistrer le mappage d'enregistrement Customer_ID correspondant.
mappedBy est utilisé dans Customer.java [Comme indiqué dans l'énoncé du problème] La table supplémentaire [CUSTOMER_ORDER] n'est plus créée. Une seule colonne dans le tableau de commande
mappedby est utilisé dans Order.java Une table supplémentaire sera désormais créée par hibernate. [name = CUSTOMER_ORDER] Order Table n'aura pas de colonne supplémentaire [Customer_ID] pour le mappage.
N'importe quel côté peut devenir propriétaire de la relation. Mais il vaut mieux choisir le côté xxxToOne.
Effet de codage -> Seul le côté propriétaire de l'entité peut changer le statut de la relation. Dans l'exemple ci-dessous, la classe BoyFriend est propriétaire de la relation. même si Girlfriend veut rompre, elle ne peut pas.
la source
Relations de table et relations d'entité
Dans un système de base de données relationnelle, il ne peut y avoir que trois types de relations de table:
Ainsi, une
one-to-many
relation de table se présente comme suit:Notez que la relation est basée sur la colonne Clé étrangère (par exemple,
post_id
) dans la table enfant.Il existe donc une seule source de vérité lorsqu'il s'agit de gérer une
one-to-many
relation de table.Maintenant, si vous prenez une relation d'entité bidirectionnelle qui correspond à la
one-to-many
relation de table que nous avons vue précédemment:Si vous regardez le diagramme ci-dessus, vous pouvez voir qu'il existe deux façons de gérer cette relation.
Dans l'
Post
entité, vous avez lacomments
collection:Et, dans le
PostComment
, l'post
association est mappée comme suit:Donc, vous avez deux côtés qui peuvent changer l'association d'entité:
comments
collection enfant, une nouvellepost_comment
ligne doit être associée à l'post
entité parente via sonpost_id
colonne.post
propriété de l'PostComment
entité, lapost_id
colonne doit également être mise à jour.Étant donné qu'il existe deux façons de représenter la colonne de clé étrangère, vous devez définir quelle est la source de vérité lorsqu'il s'agit de traduire le changement d'état d'association en modification de la valeur de la colonne de clé étrangère équivalente.
MappedBy (aka le côté inverse)
L'
mappedBy
attribut indique que le@ManyToOne
côté est en charge de la gestion de la colonne de clé étrangère, et la collection est utilisée uniquement pour récupérer les entités enfants et pour mettre en cascade les changements d'état de l'entité parente aux enfants (par exemple, la suppression du parent devrait également supprimer les entités enfants).Synchronisez les deux côtés d'une association bidirectionnelle
Désormais, même si vous avez défini l'
mappedBy
attribut et que l'@ManyToOne
association côté enfant gère la colonne de clé étrangère, vous devez toujours synchroniser les deux côtés de l'association bidirectionnelle.La meilleure façon de le faire est d'ajouter ces deux méthodes utilitaires:
Les méthodes
addComment
etremoveComment
garantissent que les deux côtés sont synchronisés. Donc, si nous ajoutons une entité enfant, l'entité enfant doit pointer vers le parent et l'entité parente doit avoir l'enfant contenu dans la collection enfant.la source