Как отношения @OnetoOne работают в JPA?

Я пытаюсь установить сопоставление один к одному между двумя объектами. Одна организация ведет записи о пользователях следующим образом:

@Entity
public class ConcreteUser implements User{

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    private String name;
    private String email;
    private int age;
    private SEX sex;
    private String accessLevel;

    public ConcreteUser() {
    }

    public ConcreteUser(String name, String email, int age, SEX sex, String accessLevel) {
        // set class properties
    }

   //
   // Some getter and setter code
   //

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

@Entity
public class SomeOtherEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "SOME_COLUMN_NAME")
    private long recordId;

    //
    // some other private fields here
    //

    @OneToOne(cascade = CascadeType.ALL)
    @PrimaryKeyJoinColumn
    private ConcreteUser concreteUser;

    public SomeOtherEntity () {
    }

    // getters and setters etc

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

@Test
public void testAddSomeOtherEntity() throws Exception {


    /* This is the user, whose primary key will be used as a foreign key in SomeOtherEntity */
    ConcreteUser user = new ConcreteUser(...);


    /* Create a new SomeOtherEntity and assign a ConcreteUser to it */
    SomeOtherEntity d = new SomeOtherEntity();
    d.setConcreteUser(user); /* I doubt if this line has any effect at all */

    // add SomeOtherEntity to table
    /* addSomeOtherEntity is translated to an HTTP request and server responds with added entity  */
    d = myService.addSomeOtherEntity(d); 
    assertNotNull(d);

    /* At this point, the recordId is generated and updated */

    // Check if this entity was added properly
    long recordId = d.getRecordId();
    SomeOtherEntity d2 = myService.getSomeOtherEntityById(recordId);
    assertNotNull(d2);

    /* This test case passes */
    assertEquals(d2.getRecordId(), d.getRecordId()); 

    /* But this test case fails */
    assertEquals(d2.getConcreteUser().getId(), d.getConcreteUser().getId());

}

Таким образом, я создаю объект SomeOtherEntity, назначаю объект ConcreteUser и сохраняю SomeOtherEntity. Однако, когда я возвращаю SomeOtherEntity, я получаю ConcreteUser, отличный от того, который я назначил ранее. В частности, ConcreteUser, которого я получаю, имеет тот же «id», что и «recordId». Это не то, чего я ожидал.

Я новичок в Spring, и я уверен, что что-то неправильно понял. На данный момент я думаю, что назначение ConcreteUser заранее SomeOtherEntity ничего не значит. Вместо этого, может быть, мне следует сначала создать и сохранить SomeOtherEntity, а затем обновить ConcreteUser? Я был бы очень признателен, если бы кто-нибудь мог дать совет и рассказать, как это делается в реальном мире. Заранее спасибо.


person sdevikar    schedule 26.11.2014    source источник


Ответы (2)


В SomeOtherEntity вы указываете сопоставление @PrimaryKeyJoinColumn для ConcreteUser. Если вы проверите документацию аннотации, вы найдете из того, что он говорит:

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

Это означает, что значение первичного ключа SomeOtherEntity используется как значение внешнего ключа для ConcreteUser.

Вместо этого вы хотите использовать аннотацию @JoinColumn.

person Wabi    schedule 26.11.2014
comment
Возможно, ему вообще не нужна аннотация @JoinColumn. - person Balázs Németh; 27.11.2014

Итак, как оказалось, существуют разные способы реализации отношения один к одному в Spring. Ниже приводится краткое и полезное введение в различные способы: Отображение "один к одному" в спящем режиме с использованием аннотаций

Проблема здесь была не во владении, а в методе, выбранном для сопоставления один к одному из трех. Согласно упомянутой выше статье, аннотация @PrimaryKeyJoinColumn используется, когда вы хотите, чтобы первичные ключи двух таблиц совпадали, что на самом деле не так. Как уже упоминалось в вопросе, тестовые примеры не удались, потому что Hibernate сопоставил две таблицы на основе первичного ключа, а не на основе того, какой объект ConcreteUser был назначен с помощью setConcreteUser

person sdevikar    schedule 27.11.2014