How to create a composite primary key which contains a @ManyToOne attribute as an @EmbeddedId in JPA?

巧了我就是萌 提交于 2019-12-17 19:22:06

问题


I'm asking and answering my own question, but i'm not assuming i have the best answer. If you have a better one, please post it!

Related questions:

  • How to set a backreference from an @EmbeddedId in JPA
  • hibernate mapping where embeddedid (?)
  • JPA Compound key with @EmbeddedId

I have a pair of classes which are in a simple aggregation relationship: any instance of one owns some number of instances of the other. The owning class has some sort of primary key of its own, and the owned class has a many-to-one to this class via a corresponding foreign key. I would like the owned class to have a primary key comprising that foreign key plus some additional information.

For the sake of argument, let's use those perennial favourites, Order and OrderLine.

The SQL looks something like this:

-- '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)
);

I would like to map this into Java using JPA. Order is trivial, and OrderLine can be handled with an @IdClass. Here's the code for that - the code is fairly conventional, and i hope you'll forgive my idiosyncrasies.

However, using @IdClass involves writing an ID class which duplicates the fields in the OrderLine. I would like to avoid that duplication, so i would like to use @EmbeddedId instead.

However, a naive attempt to do this fails:

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

OpenJPA rejects the use of that as an @EmbeddedId. I haven't tried other providers, but i wouldn't expect them to succeed, because the JPA specification requires that the fields making up an ID class be basic, not relationships.

So, what can i do? How can i write a class whose key contains @ManyToOne relationship, but is handled as an @EmbeddedId?


回答1:


I don't know of a way to do this which doesn't involve duplicating any fields (sorry!). But it can be done in a straightforward and standard way that involves duplicating only the relationship fields. The key is the @MapsId annotation introduced in JPA 2.

The embeddable key class looks like this:

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

And the embedding entity class looks like this:

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

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

The @MapsId annotation declares that the relationship field to which it is applied effectively re-maps a basic field from the embedded ID.

Here's the code for OrderId.



来源:https://stackoverflow.com/questions/7195990/how-to-create-a-composite-primary-key-which-contains-a-manytoone-attribute-as-a

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!