Чи може хтось пояснити відображений на карті в JPA та в сплячому режимі?


175

Я новачок у сплячому режимі і мені потрібно використовувати відносини «один-багато-багато» та «багато-до-одного». Це двосторонні відносини в моїх об'єктах, щоб я міг переходити з будь-якого напрямку. mappedByце рекомендований шлях для цього, однак я не міг цього зрозуміти. Може хтось пояснить:

  • який рекомендований спосіб його використання?
  • яку мету вона вирішує?

Заради мого прикладу, ось мої заняття з анотаціями:

  • Airline ВЛАСНІЙ багато AirlineFlights
  • Багато хто AirlineFlights належить до ОДНОГО Airline

Авіакомпанія :

@Entity 
@Table(name="Airline")
public class Airline {
    private Integer idAirline;
    private String name;

    private String code;

    private String aliasName;
    private Set<AirlineFlight> airlineFlights = new HashSet<AirlineFlight>(0);

    public Airline(){}

    public Airline(String name, String code, String aliasName, Set<AirlineFlight> flights) {
        setName(name);
        setCode(code);
        setAliasName(aliasName);
        setAirlineFlights(flights);
    }

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="IDAIRLINE", nullable=false)
    public Integer getIdAirline() {
        return idAirline;
    }

    private void setIdAirline(Integer idAirline) {
        this.idAirline = idAirline;
    }

    @Column(name="NAME", nullable=false)
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = DAOUtil.convertToDBString(name);
    }

    @Column(name="CODE", nullable=false, length=3)
    public String getCode() {
        return code;
    }
    public void setCode(String code) {
        this.code = DAOUtil.convertToDBString(code);
    }

    @Column(name="ALIAS", nullable=true)
    public String getAliasName() {
        return aliasName;
    }
    public void setAliasName(String aliasName) {
        if(aliasName != null)
            this.aliasName = DAOUtil.convertToDBString(aliasName);
    }

    @OneToMany(fetch=FetchType.LAZY, cascade = {CascadeType.ALL})
    @JoinColumn(name="IDAIRLINE")
    public Set<AirlineFlight> getAirlineFlights() {
        return airlineFlights;
    }

    public void setAirlineFlights(Set<AirlineFlight> flights) {
        this.airlineFlights = flights;
    }
}

Авіакомпанія:

@Entity
@Table(name="AirlineFlight")
public class AirlineFlight {
    private Integer idAirlineFlight;
    private Airline airline;
    private String flightNumber;

    public AirlineFlight(){}

    public AirlineFlight(Airline airline, String flightNumber) {
        setAirline(airline);
        setFlightNumber(flightNumber);
    }

    @Id
    @GeneratedValue(generator="identity")
    @GenericGenerator(name="identity", strategy="identity")
    @Column(name="IDAIRLINEFLIGHT", nullable=false)
    public Integer getIdAirlineFlight() {
        return idAirlineFlight;
    }
    private void setIdAirlineFlight(Integer idAirlineFlight) {
        this.idAirlineFlight = idAirlineFlight;
    }

    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name="IDAIRLINE", nullable=false)
    public Airline getAirline() {
        return airline;
    }
    public void setAirline(Airline airline) {
        this.airline = airline;
    }

    @Column(name="FLIGHTNUMBER", nullable=false)
    public String getFlightNumber() {
        return flightNumber;
    }
    public void setFlightNumber(String flightNumber) {
        this.flightNumber = DAOUtil.convertToDBString(flightNumber);
    }
}

Редагувати:

Схема бази даних:

Авіакомпанія має idAirline, оскільки ForeignKey, а авіакомпанія не має idAirlineFlight. Це робить AirlineFlights власником / ідентифікаційною особою?

Теоретично я хотів би, щоб авіакомпанія була власником авіаліній.

введіть тут опис зображення

Відповіді:


151

Вказавши @JoinColumnна обох моделях, ви не маєте двосторонніх відносин. У вас є двосторонні стосунки, і дуже заплутане відображення цього при цьому. Ви говорите обом моделям, що їм "належить" стовпець IDAIRLINE. Дійсно тільки один з них насправді повинен! «Нормальний» Справа в тому , щоб взяти на себе @JoinColumnгеть з @OneToManyбоку цілком, і замість того, щоб додати mappedBy до @OneToMany.

@OneToMany(cascade = CascadeType.ALL, mappedBy="airline")
public Set<AirlineFlight> getAirlineFlights() {
    return airlineFlights;
}

Це говорить Гібернатові: "Перегляньте власність боба під назвою" авіакомпанія "на те, що у мене є колекція, щоб знайти конфігурацію".


2
Я трохи збентежений вашим описом у підсумку про mappedBy. Чи має значення, як організовано все в db? @DB: AirlineFlights має idAirline як зовнішній ключ. Авіакомпанія просто має idAirline в якості основного ключа і не зберігає інформацію про AirlineFlights @ DB.
brainydexter

10
Так, це має значення. Назва в mappedBy вказує Hibernate, де знайти конфігурацію для JoinColumn. (Про метод getAirline () з AirlineFlight.) Те , як ви замепілі покласти JoinColumn на авіакомпанії, ви повідомляєте Авіакомпанію , що є відповідальним за підтримання значень над у іншій таблиці. Можна сказати Суб’єкту, що він "є власником" стовпця в іншій таблиці і несе відповідальність за його оновлення. Зазвичай це не те, що ти хочеш робити і може спричинити проблеми із виконанням операторів SQL.
Affe

Перегляньте редагування. На рівні БД, авіакомпанія AirlineFlight володіє idAirline як стовпець із зовнішнім ключем. Отже, JoinColumn слід поставити на клас / таблицю авіакомпанії airline у ​​відповідному ManytoOne, оскільки їй належить цей стовпець?
brainydexter

Так, я б рекомендував робити так. Це найменш складний варіант, і вам, здається, нічого іншого не потрібно.
Affe

"повністю зніміть @JoinColumn зі сторони @OneToMany" ви маєте на увазі @ManyToOneсторону, правда?
nbro

284

MappedBy сигналізує про сплячку, що ключ до стосунків знаходиться з іншого боку.

Це означає, що хоча ви зв’язуєте 2 таблиці разом, лише одна з цих таблиць має обмеження зовнішнього ключа до іншої. MappedBy дозволяє все-таки посилатися з таблиці, що не містить обмеження, до іншої таблиці.


3
ви можете, будь ласка, уточнити трохи більше?
Олександр Сурафель

1
@Kurt Du Bois, чому б ти використовував, mappedByа не визначав двосторонній (із обмеженнями Foreign_key на кожній стороні)?
Кевін Мередіт

6
Тому що іноді просто не має сенсу ставити ключ з обох сторін. Скажімо, наприклад, у вас є компанія та портативний портал. Портативний портал належить лише одній компанії, але компанія матиме декілька портативних портативних пристроїв.
Курт Дю Буа

Вибачте хлопця-редактора за те, що я відмовив мою відповідь, але доданої вартості у вашій редакції взагалі не було. Останнє речення навіть не мало сенсу.
Курт Дю Буа

@KurtDuBois настільки відображений, щоб побачити, як створювати свою базу даних, тобто ур, використовуючи mappedby, чи не перезимує на стороні Java, веде себе подібним чином.

22

mappedbyговорить сам за себе, він говорить зимуючим не відображати це поле. це вже відображено за цим полем [name = "field"].
поле знаходиться в іншому об'єкті (name of the variable in the class not the table in the database)..

Якщо цього не зробити, сплячка відобразить це два відношення, оскільки це не однакове відношення

тому нам потрібно сказати сплячим зробити картування лише в одну сторону і скоординувати між ними.


не відображається mappedBy? Тому що, не використовуючи mappedBy, я отримую той самий результат, тобто двонаправлене відображення об’єктів
фрілансер

ви не можете використовувати on2many та many2one, не використовуючи mappedBy в одній із сторон, те саме для Many2many, ви повинні використовувати mappedBy в одну сторону
Charif DZ

Дякуємо, що вказали, що означає значення атрибута, яке є ім'я поля в іншій таблиці.
Габ 是 好人

2
Можливо, сплячий не завжди говорить сам за себе, але коли це робиться, принаймні, він використовує розділові знаки
Амальговінус

1
Для мене це не говорить про себе; навпаки, це дуже заплутано. Просто подивіться на кількість питань щодо того , що на насправді mappedByі inversedBy. Інші OR використовувати набагато більш розумним belongsToMany, hasManyатрибути.
Ян Боднар

12

mappedby = "об'єкт об'єкта того ж класу, створений в іншому класі"

Примітка: -Картинка може використовуватися лише в одному класі, оскільки одна таблиця повинна містити обмеження для зовнішнього ключа. якщо відображення на карті може бути застосовано з обох сторін, то воно видаляє зовнішній ключ з обох таблиць, а без стороннього ключа немає зв’язку між двома таблицями.

Примітка: - його можна використовувати для наступних приміток: - 1. @ OneTone 2. @ OneToMany 3. @ ManyToMany

Примітка --- Його не можна використовувати для наступних приміток: - 1. @ ManyToOne

Один до одного: - Виконайте з будь-якої сторони відображення, але виконайте лише одну сторону. Він видалить додатковий стовпчик обмеження зовнішнього ключа з таблиці, для якого класу він застосовується.

Наприклад, наприклад. Якщо ми застосуємо, відображений у класі Employee, на об'єкт співробітника, тоді зовнішній ключ із таблиці Employee буде видалений.


12

Відносини таблиці та відносини сутності

У реляційній системі баз даних one-to-manyвідносини таблиці виглядають так:

<code> співвідношення таблиці «один до багатьох» </code>

Зауважте, що взаємозв'язок заснований на стовпці "Зовнішній ключ" (наприклад, post_id) у дочірній таблиці.

Отже, є єдине джерело істини, коли мова йде про управління one-to-manyвідносинами таблиці.

Тепер, якщо ви берете двонаправлене відношення сутності, яке відображає на one-to-manyтаблиці відносини, які ми бачили раніше:

Двонаправлена ​​асоціація <code> One-To-Many </code>

Якщо ви подивитеся на діаграму вище, ви побачите, що є два способи управління цим взаємозв'язком.

У Postсутності ви маєте commentsколекцію:

@OneToMany(
    mappedBy = "post",
    cascade = CascadeType.ALL,
    orphanRemoval = true
)
private List<PostComment> comments = new ArrayList<>();

І, в PostComment, то postоб'єднання відображається наступним чином :

@ManyToOne(
    fetch = FetchType.LAZY
)
@JoinColumn(name = "post_id")
private Post post;

Оскільки є два способи подання стовпця "Зовнішній ключ", ви повинні визначити, що є джерелом істини, коли мова заходить про перетворення зміни стану асоціації у його еквівалентну модифікацію значення стовпця "Зовнішній ключ".

MappedBy

mappedByАтрибут говорить про те , що @ManyToOneсторона відповідає за управління стовпцем зовнішнього ключа, а колекція використовується тільки для вилучення дочірніх об'єктів і каскадних батьківської сутність змін стану дітей (наприклад, видалення батька повинен також видалити дочірні об'єкти).

Синхронізуйте обидві сторони двостороннього об'єднання

Тепер, навіть якщо ви визначили mappedByатрибут і @ManyToOneасоціація на стороні дитини керує стовпцем Іноземний ключ, вам все одно потрібно синхронізувати обидві сторони двонаправленої асоціації.

Найкращий спосіб зробити це - додати ці два корисні методи:

public void addComment(PostComment comment) {
    comments.add(comment);
    comment.setPost(this);
}

public void removeComment(PostComment comment) {
    comments.remove(comment);
    comment.setPost(null);
}

Методи addCommentта removeCommentметоди забезпечують синхронізацію обох сторін. Отже, якщо ми додамо дочірнє ціле, то дочірнє сутність повинно вказувати на батьків, і материнське підприємство повинно мати дитину, що міститься в дочірній колекції.

Щоб отримати докладнішу інформацію про найкращий спосіб синхронізації всіх типів двонаправлених об'єднань, перегляньте цю статтю .


0

Ви почали з картографуванням ManyToOne, потім поставили відображення OneToMany так само, як і для двонаправленого способу. Тоді на стороні OneToMany (зазвичай це ваша батьківська таблиця / клас), ви повинні згадати "mappedBy" (картографування проводиться за та дочірньою таблицею / класом), тому сплячий режим не створить таблицю відображення EXTRA в БД (наприклад, TableName = parent_child).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.