Как создать идентификатор на основе двух внешних ключей в JPA / Hibernate? - PullRequest
2 голосов
/ 19 июля 2010

У меня простой вопрос относительно объявления сущностей в JPA.У меня есть сущность с 2 внешними ключами, которые не равны NULL и образуют уникальное ограничение.Сначала я думал о составном ключе, состоящем из двух внешних ключей, но я слышал, что это устаревший дизайн, а не рекомендуемый способ создания новых таблиц.

Так что мне интересно, Hibernate / JPAможет автоматически генерировать идентификатор на основе двух внешних ключей.Допустим, у меня есть следующая сущность:

@Entity
public class Foo {
  @ManyToOne
  private Bar bar;
  private int i;
}

(я пропустил теги not null и uniqueConstraint, чтобы сделать код более читабельным)

Я знаю, что могу просто добавить поле id с помощью GeneratedValueи позвольте моей БД сгенерировать ключ (в моем примере MySQL с auto_increment), но это мне кажется неэффективным, так как включает запрос к базе данных и запрос ее генерирования уникального значения идентификатора.

Есть ли способгенерации идентификатора, который не является составным (то есть типа int или long), на основе идентификатора класса "Bar" и значения целого числа "i", поскольку эти два значения уже образуют уникальное ограничение?

Ответы [ 3 ]

5 голосов
/ 19 июля 2010

Вы можете проверить главу 7 « Сохранение Java с Hibernate ».

Вы можете смоделировать составной ключ как Встраиваемый :

import javax.persistence.*;
import java.io.Serializable;

@Entity
public class Foo {

    @Embeddable
    public static class Id implements Serializable {
        @Column(name = "bar_id_col")
        private Long barId;

        @Column(name = "i_col")
        private int i;

        public Id() {
        }

        public Id(Long barId, int i) {
            this.barId = barId;
            this.i = i;
        }

        @Override
        public boolean equals(final Object o) {
            if (this == o) {
                return true;
            }
            if (!(o instanceof Id)) {
                return false;
            }

            final Id id = (Id) o;

            if (i != id.i) {
                return false;
            }
            if (barId != null ? !barId.equals(id.barId) : id.barId != null) {
                return false;
            }

            return true;
        }

        @Override
        public int hashCode() {
            int result = barId != null ? barId.hashCode() : 0;
            result = 31 * result + i;
            return result;
        }
    }

    @EmbeddedId
    private Id id = new Id();

    @ManyToOne
    @JoinColumn(name = "bar_id_col", insertable = false, updatable = false)
    private Bar bar;

    private int i;

    public Foo() {
    }

    public Foo(Bar bar, int i) {
        // set fields
        this.Bar = bar;
        this.i=i;
        // set identifier values
        this.id.barId = bar.getId();
        this.id.i = i;
    }

}

Здесь я предполагаю, что Бар выглядит так:

import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
public class Bar {

    @Id
    Long id;

    public Long getId() {
        return id;
    }

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

Обратите внимание, что это отображает bar_id_col дважды. По этой причине вставляемый = ложь, обновляемый = ложь во второй ссылке.

Это сложно, но если вы действительно хотите сделать это так, это возможно.

Удачи, J.

1 голос
/ 19 июля 2010

Я думаю, вы должны переосмыслить свой дизайн здесь;вероятно, имеет больше смысла иметь составной ключ или, лучше, идентификатор.

Обоснование создания значений первичного ключа из внешних ключей может иметь неприятные последствия.Это связано с тем, что первичные ключи не предназначены для изменения - что если изменить одно из значений внешнего ключа?Следует ли восстановить значение первичного ключа?И нужно ли в результате изменять ссылки на столбцы в других таблицах?В любом случае, JPA требует, чтобы первичные ключи не менялись, поэтому вам лучше иметь естественный или суррогатный ключ.

Усилия по написанию генератора лучше потратить на обеспечение правильности модели.

1 голос
/ 19 июля 2010

Я думаю, что «неэффективность» настолько незначительна, что в 99,99% случаев ее можно игнорировать.

Для БД, поддерживающей столбец с автоинкрементом, нет дополнительного запроса туда и обратно для запроса на создание идентификатора.Для БД, которая не поддерживает столбец с автоинкрементом (например, Oracle), Hibernate сделал некоторую оптимизацию, чтобы уменьшить доступ к БД для генерации идентификатора (например, получить значение последовательности, умножить на 50 и использовать следующие 50 значений из результата в качестве идентификатора новых объектов)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...