В двунаправленной ассоциации JPA OneToMany/ManyToOne, что предназначено “обратной стороной ассоциации”?

В этих примерах на Ссылке на примечание TopLink JPA:

Пример 1-59 @OneToMany - клиентский класс с дженериками

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

Пример 1-60 @ManyToOne - класс порядка с дженериками

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

Мне что кажется Customer объект является владельцем ассоциации. Однако в объяснении mappedBy атрибут в том же документе, это записано это:

если отношения двунаправлены, то установленный mappedBy элемент на обратном (невладение) сторона ассоциации к названию поля или свойства, которое владеет отношениями как Примером 1-60 шоу.

Однако, если я не ошибаюсь, это похоже в примере, mappedBy на самом деле указан на стороне владения ассоциации, а не стороне невладения.

Таким образом, мой вопрос в основном:

  1. В двунаправленной (one-to-many/many-to-one) ассоциации, которая из объектов является владельцем? Как мы можем определять Одну сторону как владельца? Как мы можем определять сторону Многих как владельца?

  2. Что предназначено "обратной стороной ассоциации"? Как мы можем определять Одну сторону как инверсию? Как мы можем определять сторону Многих как инверсию?

160
задан Marcel 30 July 2015 в 20:55
поделиться

1 ответ

Чтобы понять это, нужно сделать шаг назад. В OO заказчик владеет заказами (заказы представляют собой список в объекте клиента). Без покупателя не может быть заказа. Таким образом, клиент выглядит владельцем заказов.

Но в мире SQL один элемент фактически будет содержать указатель на другой. Поскольку на N заказов приходится 1 клиент, каждый заказ содержит внешний ключ клиента, которому он принадлежит. Это «соединение», и это означает, что заказ «владеет» (или буквально содержит) соединение (информацию). Это полная противоположность объектно-ориентированному / модельному миру.

Это может помочь понять:

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

Обратной стороной является объектно-ориентированный «владелец» объекта, в данном случае заказчик. У клиента нет столбцов в таблице для хранения заказов, поэтому вы должны указать ему, где в таблице заказов он может сохранить эти данные (что происходит через mappedBy ).

Другой распространенный пример - деревья с узлами, которые могут быть как родителями, так и потомками. В этом случае два поля используются в одном классе:

public class Node {
    // Again, this is managed by Hibernate.
    // There is no matching column in the database.
    @OneToMany(cascade = CascadeType.ALL) // mappedBy is only necessary when there are two fields with the type "Node"
    private List<Node> children;

    // This field exists in the database.
    // For the OO model, it's not really necessary and in fact
    // some XML implementations omit it to save memory.
    // Of course, that limits your options to navigate the tree.
    @ManyToOne
    private Node parent;
}

Это объясняет принцип работы "многие к одному" при проектировании "внешнего ключа". Есть второй подход, который использует другую таблицу для поддержания отношений. Это означает, что для нашего первого примера у вас есть три таблицы: одна с клиентами, другая с заказами и таблица из двух столбцов с парами первичных ключей (customerPK, orderPK).

Этот подход более гибкий, чем описанный выше (он может легко обрабатывать запросы «один к одному», «многие к одному», «один ко многим» и даже «многие ко многим»).Цена в том, что

  • это немного медленнее (для поддержки другой таблицы и объединения используются три таблицы вместо двух),
  • синтаксис объединения более сложен (что может быть утомительным, если вам нужно вручную написать много запросов. (например, когда вы пытаетесь что-то отладить)
  • это более подвержено ошибкам, потому что вы можете внезапно получить слишком много или слишком мало результатов, когда что-то пойдет не так в коде, который управляет таблицей соединений.

Вот почему я редко рекомендую этот подход.

296
ответ дан 23 November 2019 в 21:29
поделиться
Другие вопросы по тегам:

Похожие вопросы: