W dwukierunkowym stowarzyszeniu JPA OneToMany / ManyToOne, co oznacza "odwrotna strona Stowarzyszenia"?

W tych przykładach na odniesienie do adnotacji TopLink JPA :

Przykład 1-59 @OneToMany-Klasa Klienta Z Generikami

@Entity
public class Customer implements Serializable {
    ...
    @OneToMany(cascade=ALL, mappedBy="customer")
    public Set<Order> getOrders() { 
        return orders; 
    }
    ...
}

Przykład 1-60 @ ManyToOne - Klasa Porządkowa Z Generykami

@Entity
public class Order implements Serializable {
    ...
    @ManyToOne
    @JoinColumn(name="CUST_ID", nullable=false)
    public Customer getCustomer() { 
        return customer; 
    }
    ...
}

Wydaje mi się, że podmiot Customer jest właścicielem Stowarzyszenia. Jednak w wyjaśnieniu atrybutu mappedBy w tym samym dokumencie jest napisane, że:

Jeśli relacja jest dwukierunkowa, następnie Ustaw mappedBy element na odwrotna (nie posiadająca) strona skojarzenie z nazwą pola lub nieruchomość, która jest właścicielem związku Jak pokazuje przykład 1-60.

Jednakże, jeśli się nie mylę, wygląda na to, że w przykładzie mappedBy jest faktycznie określona po stronie właściciela Stowarzyszenia, a nie po stronie nie posiadającej.

Więc moje pytanie brzmi zasadniczo:

  1. W związku dwukierunkowym (jeden do wielu/wiele do jednego), który z podmiotów jest właścicielem? Jak czy możemy wyznaczyć jedną stronę jako właściciela? Jak możemy wyznaczyć wiele stron jako właściciela?

  2. Co oznacza "odwrotna strona Stowarzyszenia"? Jak możemy wyznaczyć jedną stronę jako odwrotność? Jak możemy wyznaczyć wiele stron jako odwrotność?

Author: Marcel, 2010-04-06

5 answers

Aby to zrozumieć, musisz zrobić krok w tył. W OO klient jest właścicielem zamówień (zamówienia są listą w obiekcie klienta). Nie może być zamówienia bez klienta. Więc klient wydaje się być właścicielem zamówień.

Ale w świecie SQL, jeden element będzie zawierał wskaźnik do drugiego. Ponieważ dla N zamówień jest 1 klient, każde zamówienie zawiera klucz obcy dla Klienta, do którego należy. To jest "połączenie", a to oznacza, że zamówienie "posiada" (lub dosłownie zawiera) połączenie (informacje). Jest to dokładnie przeciwieństwo świata OO / model.

To może pomóc zrozumieć:

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;
}

Strona odwrotna to OO "właściciel" obiektu, w tym przypadku Klient. Klient nie ma kolumn w tabeli do przechowywania zamówień, więc musisz mu powiedzieć, gdzie w tabeli zamówień może zapisać te dane(co dzieje się za pomocą mappedBy).

 286
Author: Aaron Digulla,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-01 11:24:06

Niewiarygodnie, w ciągu 3 lat nikt nie odpowiedział na twoje doskonałe pytanie z przykładami obu sposobów mapowania relacji.

Jak wspominali inni, strona "właściciela" zawiera wskaźnik (klucz obcy) w bazie danych. Możesz wyznaczyć obie strony jako właściciela, jednak jeśli oznaczysz jedną stronę jako właściciela, relacja nie będzie dwukierunkowa (strona odwrotna aka "wiele" nie będzie miała wiedzy o swoim "właścicielu"). Może to być pożądane w przypadku hermetyzacji / luźnej sprzężenie:

// "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
}

Jedynym rozwiązaniem mapowania dwukierunkowego jest posiadanie strony" wielu "własnego wskaźnika do" jedynki "i użycie atrybutu @OneToMany" mappedBy". Bez atrybutu" mappedBy " Hibernate będzie oczekiwać podwójnego mapowania (baza danych będzie miała zarówno kolumnę join, jak i tabelę join, co jest zbędne (Zwykle niepożądane)).

// "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;
}
 38
Author: Steve Jones,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-03 15:49:13

Podmiot, który ma tabelę z kluczem obcym w bazie danych, jest podmiotem posiadającym, a druga tabela, na którą wskazuje, jest podmiotem odwrotnym.

 33
Author: Venu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-10 10:43:55

Proste zasady dwukierunkowych relacji:

1.Dla wielu do jednego dwukierunkowych relacji, wiele strona jest zawsze właścicielem strony relacji. Przykład: 1 pokój ma wiele osób (osoba należy tylko jeden pokój) -> strona właścicielem jest osoba

2.Dla relacji dwukierunkowych jeden do jednego strona posiadająca odpowiada stronie, która zawiera odpowiedni klucz obcy.

3.Dla wielu do wielu relacji dwukierunkowych, każda ze Stron może być właścicielem bok.

Nadzieja może Ci pomóc.

 12
Author: Ken Block,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-24 17:37:47

Dla dwóch klas encji Customer i Order , hibernate utworzy dwie tabele.

Możliwe Przypadki:

  1. MappedBy nie jest używany w kliencie.java i porządek.Klasa java then - >

    Po stronie klienta zostanie utworzona nowa tabela [name = CUSTOMER_ORDER], która będzie mapować CUSTOMER_ID i ORDER_ID. Są to podstawowe klucze tabel klientów i zamówień. Po stronie zamówienia wymagana jest dodatkowa kolumna do zapisania odpowiedniego mapowania rekordu Customer_ID.

  2. MappedBy jest używany w kliencie.java [jak podano w instrukcji problem] Teraz dodatkowa tabela[CUSTOMER_ORDER] nie jest tworzona. Tylko jedna kolumna w tabeli Porządkowej

  3. Mappedby jest używany w kolejności.java Teraz dodatkowa tabela zostanie utworzona przez hibernate.[name = CUSTOMER_ORDER] Tabela zleceń nie będzie miała dodatkowej kolumny [Customer_ID ] do mapowania.

Każda strona może stać się właścicielem relacji. Ale lepiej wybrać xxxToOne bok.

Efekt kodowania - > tylko posiadanie strony podmiotu może zmienić status relacji. W poniższym przykładzie Klasa BoyFriend jest właścicielem związku. nawet jeśli dziewczyna chce zerwać , nie może.]}

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) {
             throw new RuntimeException(e);
         }
        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.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import java.util.List;

public class Main578_Modify {

    public static void main(String[] args) {
        final Configuration configuration = new Configuration();
        try {
            configuration.configure("hibernate.cfg.xml");
        } catch (HibernateException e) {
            throw new RuntimeException(e);
        }
        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();
    }
}
 3
Author: HakunaMatata,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-12 14:01:18