Как создать составной первичный ключ, который содержит атрибут @ManyToOne как @EmbeddedId в JPA? - PullRequest
8 голосов
/ 25 августа 2011

Я спрашиваю и отвечаю на свой вопрос , но я не предполагаю, что у меня есть лучший ответ. Если у вас есть лучший, пожалуйста, отправьте его!

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

У меня есть пара классов, которые находятся в простых отношениях агрегации: любому экземпляру одного принадлежит некоторое количество экземпляров другого. Класс-владелец имеет своего рода первичный ключ, а класс-владелец имеет множество-один для этого класса через соответствующий внешний ключ. Я хотел бы, чтобы принадлежащий класс имел первичный ключ, содержащий этот внешний ключ, а также некоторую дополнительную информацию.

Ради аргумента давайте использовать эти постоянные фавориты, Order и OrderLine.

SQL выглядит примерно так:

-- 'order' may have been a poor choice of name, given that it's an SQL keyword!
create table Order_ (
    orderId integer primary key
);
create table OrderLine (
    orderId integer not null references Order_,
    lineNo integer not null,
    primary key (orderId, lineNo)
);

Я хотел бы отобразить это на Java с использованием JPA. Order является тривиальным, и OrderLine может быть обработан с помощью @IdClass. Вот код для этого - код довольно условный, и я надеюсь, что вы простите мои идиосинкразии.

Однако использование @IdClass предполагает написание класса ID, который дублирует поля в OrderLine. Я бы хотел избежать такого дублирования, поэтому вместо этого я бы хотел использовать @EmbeddedId.

Однако наивная попытка сделать это не удалась:

@Embeddable
public class OrderLineKey {
    @ManyToOne
    private Order order;
    private int lineNo;
}

OpenJPA отвергает использование этого в качестве @EmbeddedId. Я не пробовал других провайдеров, но не ожидал, что они преуспеют, потому что спецификация JPA требует, чтобы поля, составляющие класс ID, были базовыми, а не отношениями.

Итак, что я могу сделать? Как я могу написать класс, ключ которого содержит отношение @ManyToOne, но обрабатывается как @EmbeddedId?

1 Ответ

16 голосов
/ 25 августа 2011

Я не знаю способа сделать это, который не предполагает дублирование каких-либо полей (извините!).Но это может быть сделано простым и стандартным способом, который предполагает дублирование только полей отношений.Ключом является аннотация @ MapsId , представленная в JPA 2.

Класс встраиваемого ключа выглядит следующим образом:

@Embeddable
public class OrderLineKey {
    private int orderId;
    private int lineNo;
}

А класс встраиваемой сущности выглядит следующим образом:

@Entity
public class OrderLine{
    @EmbeddedId
    private OrderLineKey id;

    @ManyToOne
    @MapsId("orderId")
    private Order order;
}

Аннотация @MapsId объявляет, что поле отношения, к которому оно применяется, эффективно повторно отображает базовое поле из встроенного идентификатора.

Вот код для OrderId .

...