171 votes

Dans une bidirectionnel JPA OneToMany/ManyToOne association, ce que l'on entend par "l'inverse du côté de l'association"?

Dans ces exemples sur TopLink JPA Annotation de Référence:

Exemple 1-59 @OneToMany - Classe De La Clientèle Avec Les 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 Les 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 de l'entité est le propriétaire de l'association. Cependant, dans l'explication de l' mappedBy d'attribut dans le même document, il est écrit que:

si la relation est bidirectionnelle, définissez ensuite la mappedBy élément sur la inverse (non propriétaire) de la association pour le nom du champ ou des biens que possède la relation à titre d'Exemple 1-60 montre.

Cependant, si je ne me trompe pas, il ressemble dans l'exemple, l' mappedBy est spécifié sur le propriétaire du côté de l'association, plutôt que les non-possesseurs d'un côté.

Donc ma question est fondamentalement:

  1. Dans bidirectionnelle (un-à-plusieurs ou plusieurs-à-un) de l'association, laquelle de ces entités est le propriétaire? Comment peut-on désigner Un côté, en tant que propriétaire? Comment peut-on désigner le côté "Plusieurs" en tant que propriétaire?

  2. Qu'entend-on par "l'inverse du côté de l'association"? Comment peut-on désigner Un côté comme de l'inverse? Comment peut-on désigner le côté "Plusieurs" comme l'inverse?

317voto

Aaron Digulla Points 143830

Pour comprendre cela, vous devez prendre du recul. Dans OO, le client détient les commandes (commandes sont d'une liste à l'objet client). Il ne peut pas être une commande sans client. Si le client semble être le propriétaire de la commande.

Mais dans le monde SQL, un élément contiendra en fait un pointeur vers l'autre. Depuis il y a 1 client pour les ordonnances N, chaque commande contient une clé étrangère vers le client auquel il appartient. C'est la "connexion" et cela signifie que la commande est "propriétaire" (ou littéralement contient), la connexion (de l'information). C'est exactement le contraire de l'OO/modèle du monde.

Cela peut aider à comprendre:

public class Customer {
     // This field doesn't exist in the database
     // It is simulated with a SQL query
     // "OO speak": Customer owns the orders
     private List<Order> orders;
}

public class Order {
     // This field actually exists in the DB
     // In a purely OO model, we could omit it
     // "DB speak": Order contains a foreign key to customer
     private Customer customer;
}

L'inverse de la côté est de la OO "propriétaire" de l'objet, dans ce cas le client. Le client n'a pas de colonnes dans le tableau pour stocker les commandes, vous devez lui indiquer où dans le tableau de commande, il peut enregistrer ces données (ce qui arrive via mappedBy).

45voto

Steve Jones Points 537

Incroyablement, en 3 ans, personne n'a répondu à votre excellente question avec des exemples de ces deux façons à la carte de la relation.

Comme mentionné par d'autres, le "propriétaire" côté contient le pointeur (clé étrangère) dans la base de données. Vous pouvez désigner chaque côté en tant que propriétaire, cependant, si vous désignez Un côté, en tant que propriétaire, la relation ne va pas être bidirectionnelle (l'inverse aka côté "plusieurs" n'aura pas connaissance de son "propriétaire"). Cela peut être souhaitable pour l'encapsulation/couplage lâche:

// "One" Customer owns the associated orders by storing them in a customer_orders join table
public class Customer {
    @OneToMany(cascade = CascadeType.ALL)
    private List<Order> orders;
}

// if the Customer owns the orders using the customer_orders table,
// Order has no knowledge of its Customer
public class Order {
    // @ManyToOne annotation has no "mappedBy" attribute to link bidirectionally
}

La seule mise en correspondance bidirectionnelle solution est d'avoir le côté "plusieurs" de ses propres pointeur vers le "un", et utiliser le @OneToMany "mappedBy" attribut. Sans le "mappedBy" attribut Hibernate, s'attendent à une double cartographie (la base de données aurait à la fois la colonne de jointure et de la table de jointure, qui est redondante (généralement indésirables)).

// "One" Customer as the inverse side of the relationship
public class Customer {
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "customer")
    private List<Order> orders;
}

// "many" orders each own their pointer to a Customer
public class Order {
    @ManyToOne
    private Customer customer;
}

37voto

Venu Points 179

L'entité qui possède la table avec clé étrangère dans la base de données est l'entité propriétaire, et de l'autre table, cours pointé, est l'inverse de l'entité.

14voto

Ken Block Points 383

Règles simples de les relations bidirectionnelles:

1.Pour plusieurs-à-un les relations bidirectionnelles, le côté "plusieurs" est toujours le propriétaire du côté de la relation. Exemple: 1 Chambre a beaucoup de Personne (dont une Personne fait partie d'une Chambre uniquement) -> posséder côté est Personne

2.Pour un-à-un les relations bidirectionnelles, le propriétaire de côté correspond à la partie qui contient la clé étrangère correspondante.

3.Pour plusieurs-à-plusieurs les relations bidirectionnelles, de chaque côté peut être le propriétaire de côté.

L'espoir peut vous aider.

4voto

Manish Points 175

Pour les deux Classes d'Entité Client et de l'Ordre , hibernate va créer deux tables.

Cas Possibles:

  1. mappedBy n'est pas utilisé dans Customer.java et Order.java Classe->

    À côté client une nouvelle table sera créée[nom = CUSTOMER_ORDER] qui va garder la cartographie de CUSTOMER_ID et ORDER_ID. Ce sont des clés primaires des Tables Client et Commande. Lors de la Commande le côté d'une colonne supplémentaire est nécessaire pour enregistrer le correspondant Customer_ID enregistrement de la cartographie.

  2. mappedBy est utilisé dans Customer.java [Comme donné dans l'énoncé du problème] Maintenant, table supplémentaire[CUSTOMER_ORDER] n'est pas créé. Une seule colonne dans la Table Commande

  3. mappedby est utilisé dans Order.java Maintenant, table supplémentaire sera créé par hibernate.[name = CUSTOMER_ORDER] Tableau de commande n'aura pas de colonne supplémentaire [Customer_ID ] pour la correspondance.

Un Côté peut être faite Propriétaire de la relation. Mais il est préférable de choisir xxxToOne côté.

Codage effet - > Seulement Posséder côté de l'entité peut changer l'état des relations. Dans l'exemple ci-dessous Copain de classe est propriétaire de la relation. même si la petite Amie veut rompre , elle ne peut pas.

 import javax.persistence.*;
 import java.util.ArrayList;
 import java.util.List;

  @Entity
  @Table(name = "BoyFriend21")
  public class BoyFriend21 {

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE ,
        generator = "Boy_ID")
@SequenceGenerator(name = "Boy_ID" ,
        sequenceName = "Boy_ID_SEQUENCER",
        initialValue = 10,allocationSize = 1)
private Integer id;

@Column(name = "BOY_NAME")
private String name;

@OneToOne(cascade = {CascadeType.ALL})
private GirlFriend21 girlFriend;

public BoyFriend21(String name) {
    this.name = name;
}

public BoyFriend21() {
}

public Integer getId() {
    return id;
}

public void setId(Integer id) {
    this.id = id;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public BoyFriend21(String name, GirlFriend21 girlFriend) {
    this.name = name;
    this.girlFriend = girlFriend;
}

public GirlFriend21 getGirlFriend() {
    return girlFriend;
}

public void setGirlFriend(GirlFriend21 girlFriend) {
    this.girlFriend = girlFriend;
}
 }


   import org.hibernate.annotations.*;

   import javax.persistence.*;
   import javax.persistence.CascadeType;
   import javax.persistence.Entity;
   import javax.persistence.Table;
   import java.util.ArrayList;
   import java.util.List;

   @Entity 
   @Table(name = "GirlFriend21")
   public class GirlFriend21 {
    @Id
   @GeneratedValue(strategy = GenerationType.SEQUENCE ,
         generator = "Girl_ID")
      @SequenceGenerator(name = "Girl_ID" ,
        sequenceName = "Girl_ID_SEQUENCER",
        initialValue = 10,allocationSize = 1)
private Integer id;

@Column(name = "GIRL_NAME")
private String name;

@OneToOne(cascade = {CascadeType.ALL},mappedBy = "girlFriend")
private BoyFriend21 boyFriends = new BoyFriend21();

public GirlFriend21() {
}

public GirlFriend21(String name) {
    this.name = name;
}


public Integer getId() {
    return id;
}

public void setId(Integer id) {
    this.id = id;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public GirlFriend21(String name, BoyFriend21 boyFriends) {
    this.name = name;
    this.boyFriends = boyFriends;
}

public BoyFriend21 getBoyFriends() {
    return boyFriends;
}

public void setBoyFriends(BoyFriend21 boyFriends) {
    this.boyFriends = boyFriends;
}

}

      import org.hibernate.HibernateException;
      import org.hibernate.Session;
      import org.hibernate.SessionFactory;
      import org.hibernate.cfg.Configuration;

        import java.util.Arrays;

          public class Main578_DS {

          public static void main(String[] args) {
          final Configuration configuration = new Configuration();
         try {
                 configuration.configure("hibernate.cfg.xml");
               } catch (HibernateException e) {
              e.printStackTrace();
          }
    final SessionFactory sessionFactory = configuration.buildSessionFactory();
    final Session session = sessionFactory.openSession();
    session.beginTransaction();

    final BoyFriend21 clinton = new BoyFriend21("Bill Clinton");

    final GirlFriend21 monica = new GirlFriend21("monica lewinsky");

    clinton.setGirlFriend(monica);
    session.save(clinton);

    session.getTransaction().commit();
    session.close();
}

}

  import org.hibernate.HibernateException;

import org.mise en veille prolongée.Session; import org.mise en veille prolongée.SessionFactory; import org.mise en veille prolongée.cfg.Configuration;

importer java.util.Liste;

public class Main578_Modify {

public static void main(String[] args) {
    final Configuration configuration = new Configuration();
    try {
        configuration.configure("hibernate.cfg.xml");
    } catch (HibernateException e) {
        e.printStackTrace();
    }
    final SessionFactory sessionFactory = configuration.buildSessionFactory();
    final Session session1 = sessionFactory.openSession();
    session1.beginTransaction();

    GirlFriend21 monica = (GirlFriend21)session1.load(GirlFriend21.class,10);  // Monica lewinsky record has id  10.
    BoyFriend21 boyfriend = monica.getBoyFriends();
    System.out.println(boyfriend.getName()); // It will print  Clinton Name
    monica.setBoyFriends(null); // It will not impact relationship

    session1.getTransaction().commit();
    session1.close();

    final Session session2 = sessionFactory.openSession();
    session2.beginTransaction();

    BoyFriend21 clinton = (BoyFriend21)session2.load(BoyFriend21.class,10);  // Bill clinton record

    GirlFriend21 girlfriend = clinton.getGirlFriend();
    System.out.println(girlfriend.getName()); // It will print Monica name.
    //But if Clinton[Who owns the relationship as per "mappedby" rule can break this]
    clinton.setGirlFriend(null);
    // Now if Monica tries to check BoyFriend Details, she will find Clinton is no
    // more her boyFriend
    session2.getTransaction().commit();
    session2.close();


    final Session session3 = sessionFactory.openSession();
    session1.beginTransaction();

    monica = (GirlFriend21)session3.load(GirlFriend21.class,10);  // Monica lewinsky record has id  10.
    boyfriend = monica.getBoyFriends();

    System.out.println(boyfriend.getName()); // Does not print Clinton Name

    session3.getTransaction().commit();
    session3.close();
}

}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X