@PrimaryKeyJoinColumn не выбирает общий ключ - PullRequest
0 голосов
/ 30 ноября 2018

Раньше у меня работала @PrimaryKeyJoinColumn, теперь я пытаюсь с весенней загрузкой, и я не могу понять, чего мне не хватает, это очень странно, так как кажется, что я все сделала правильно:

Человеккласс:

    @Table(name = "PERSON")
@Entity

@Getter
@Setter
public class Person {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "ID")
    private Long id;


    @Column(name = "NAME")
    private String name;

    @OneToOne(cascade = CascadeType.PERSIST)
    @PrimaryKeyJoinColumn
    private Department department;
}

класс отдела:

    @Table(name = "DEPARTMENT")
@Entity
@Getter
@Setter
public class Department {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "ID")
    private Long id;

    @Column(name = "NAME")
    private String name;


    @OneToOne(mappedBy = "department")
    private Person person;
}

класс обслуживания:

   @Transactional
    public void addPerson() {
        Person person = new Person();
        person.setName("person 1");
        Department department = new Department();
        department.setName("test");
        department.setPerson(person);
        person.setDepartment(department);
        personRepository.save(person);
    }

Вот что я получаю в БД: Таблица Person:

ID   Name
13  person 1

Таблица отдела:

ID  Name
18  test

Желаемый результат: оба идентификатора должны быть идентичны (идентификатор лица должен быть 18, а не 13), есть идеи?


Обновление : hibernate всегда пытается вставить Person без ID, поэтому, если я удаляю автоинкремент из Person ID и пытается вставить человека с существующим отделом, я получаю:

Hibernate: insert into person (name) values (?)

Field 'id' doesn't have a default value

Обновление 2: кажется, @PrimaryKeyJoinColumn не будет обрабатывать генерацию идентификатора как класс отдела, поэтому мне нужно использовать генератор.Я удивляюсь, потому что те же самые аннотации работ в Inheritance объединялись, ничего не делая с идентификатором подкласса.Поэтому я ожидаю ответа, объясняющего, почему генерация идентификаторов работает в объединенном наследовании, в то время как OneToOne нужен генератор

1 Ответ

0 голосов
/ 01 декабря 2018

Несмотря на то, что называть целый Отдел только для ОДНОГО человека (это обычно группировка многих людей) - это, по крайней мере, неверное наименование, я полагаю, что вы действительно ищете связь OneToOne с общим PRIMARY KEY.

Лучшее решение (оптимальная память, скорость и обслуживание) @MapsId:

@Getter
@Setter
@Entity
public class Person {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    @OneToOne(mappedBy = "person", fetch = FetchType.LAZY)
    private Department department;
}

@Getter
@Setter
@Entity
public class Department {
    @Id // Note no generation
    private Long id;

    private String name;

    @OneToOne(fetch = FetchType.LAZY)
    @MapsId
    @JoinColumn(name = "id", foreignKey = @ForeignKey(name = "department_belongs_to_person"))
    private Person person;
}

Здесь Департамент владеет отношением (владение обычно означает, что в базе данных будет столбец с FK, но здесь они просто используют первичный ключ)и владеет FK, который привязывает свой PK к одному, сгенерированному Person.

Обратите внимание, что отношение является OneToOne, двунаправленным, с общим PK в качестве FK.Это считается наилучшей практикой, но имеет один небольшой недостаток, заключающийся в необходимости писать один метод получения.:)

Источники: https://vladmihalcea.com/the-best-way-to-map-a-onetoone-relationship-with-jpa-and-hibernate/

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

РЕДАКТИРОВАТЬ

Я могу ошибаться (я уверен, что сейчас - смотрите комментарии), но, насколько мне известно, поддержание идентификаторов равноне то, что JPA указывает.В основном это может быть указано:

"Эй, вы, ребята (Person, Department), братья (OneToOne) и оба это знают (двунаправленный с mappedBy =" person "в сущности Person). Вы будете старше, браткоторый будет генерировать идентификаторы (Person имеет @GeneratedValue), и вы будете тем самым, у которого должно быть то же самое. Вы будете использовать эти поля (идентификаторы, одно сгенерированное, второе нет) для подключения (@PrimaryKeyJoinColumn). "

WhatЯ пытаюсь сказать, что если вы говорите «это связывает вас», это не значит, что они синхронизированы - вы должны это гарантировать.

Теперь о том, как это обеспечить - известен @MapsIdчтобы быть лучшим.

Если вы ищете другие подходы, есть также установка идентификатора вручную, чтобы он был таким же, как и другой, с #setDepartment (Department), где вы должны установить идентификатор отдела таким же, как и вызывающий абонент (но это толькоработает, если у указанного Person уже есть сгенерированный идентификатор, что в основном нарушает идею).

Другой известный мне вариант - использование стратегии стороннего генератора.

Person:

@Id
@GeneratedValue
private long id;

@OneToOne(mappedBy="person")
private Department department;

Отдел:

@Id
@GeneratedValue(generator="gen")
@GenericGenerator(name="gen", strategy="foreign", parameters=@Parameter(name="property", value="person"))
private long id;

@OneToOne
@PrimaryKeyJoinColumn
private Person person;

Теперь - этот использует специфичные для hibernate аннотации и не является чистым JPA.

...