JPA + Spring: сопоставление столбца внешнего ключа с идентификатором на основе значения, полученного до сохранения сущности - PullRequest
0 голосов
/ 09 апреля 2019

Пожалуйста, извините, если это глупый вопрос, но я очень плохо знаком с JPA и Spring.Мне интересно, может ли кто-нибудь помочь с приведенной ниже проблемой, так как я много занимался поиском в StackOverflow и в Google, но не смог найти ни одного примера для своего варианта использования.Возможно, мне не хватает ключевого слова, так как я не знаю, как этот вид отображения называется в JPA.

Итак, я пытаюсь разработать REST API для извлечения и вставки записи из /в базе данных и для которого у меня есть две таблицы, а именно CLIENT_MASTER и TITLE.

Схема для CLIENT_MASTER выглядит следующим образом:

CREATE TABLE CLIENT_MASTER (
   ID INT GENERATED BY DEFAULT AS IDENTITY(START WITH 1000),
   TITLE_ID INT,
   FIRST_NAME VARCHAR(255),
   MIDDLE_NAME VARCHAR(255),
   LAST_NAME VARCHAR(255),
   PRIMARY KEY (ID)
);

Аналогично, схема для таблицы TITLE:

CREATE TABLE TITLE (
   ID INT GENERATED BY DEFAULT AS IDENTITY,
   TITLE VARCHAR(10),
   PRIMARY KEY (ID)
);

CLIENT_MASTERТаблица имеет следующее ограничение внешнего ключа:

ALTER TABLE CLIENT_MASTER ADD CONSTRAINT TITLE_ID FOREIGN KEY (TITLE_ID) REFERENCES TITLE;

Объект для обеих таблиц определен, как показано ниже,

import java.io.Serializable;
...
import lombok.Setter;

@Entity
@Table(name = "CLIENT_MASTER")
@Getter
@Setter
public class ClientMaster implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "ID", updatable = false, nullable = false)
    private Integer id;

    @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    @JoinColumn(name = "TITLE_ID")
    private Title title;

    @Column(name = "FIRST_NAME")
    private String firstName;

    @Column(name = "MIDDLE_NAME")
    private String middleName;

    @Column(name = "LAST_NAME")
    private String lastName;
}

import java.io.Serializable;
....
import lombok.Setter;

@Entity
@Table(name = "TITLE")
@Getter
@Setter
public class Title implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "ID", updatable = false, nullable = false)
    private Integer id;

    @Column(name = "TITLE")
    private String title;
}

И в моем контроллере покоя у меня есть ниже, чтобы вставить новыйclient

@RequestMapping(method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseStatus(value = HttpStatus.OK)
public ResponseEntity<?> create(@RequestBody ClientMaster cm) {
    cmrepository.create(cm);
    HttpHeaders headers = new HttpHeaders();
    ControllerLinkBuilder linkBuilder = linkTo(methodOn(CompanyController.class).get(cm.getId()));
    headers.setLocation(linkBuilder.toUri());
    return new ResponseEntity<>(headers, HttpStatus.CREATED);
}

где cmrepository - это экземпляр,

@Repository
public class CMRepository {

@PersistenceContext
private EntityManager entityManager;

@Override
public void create(ClientMaster cm) {
    entityManager.persist(cm);

 }
}

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

{
    "title": {
        "title": "Mr"
    },
    "firstName": "XXX",
    "middleName": "YYY",
    "lastName": "ZZZ",
}

С учетом вышеизложенного, текущее поведение таково, что для каждой вставки записи в CLIENT_TABLE создается новая запись в таблице TITLE, которая не нужна мне.

Может ли кто-нибудь указать мне правильное направление относительно того, как этого можно достичь?

Большое спасибо.

Ответы [ 3 ]

0 голосов
/ 09 апреля 2019

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

0 голосов
/ 09 апреля 2019

Спасибо, ребята

Я последовал предложению Maciej, и теперь мой контроллер выглядит так, как показано ниже

@RequestMapping(method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseStatus(value = HttpStatus.OK)
public ResponseEntity<?> create(@RequestBody ClientMaster company) {
    //fetch and set title. 
    company.setTitle(titleService.get(company.getTitle().getTitle()));
    companyService.create(company);
    HttpHeaders headers = new HttpHeaders();
    ControllerLinkBuilder linkBuilder = linkTo(methodOn(CompanyController.class).get(company.getId()));
    headers.setLocation(linkBuilder.toUri());
    return new ResponseEntity<>(headers, HttpStatus.CREATED);
}
0 голосов
/ 09 апреля 2019

Невозможно, чтобы поставщик сохраняемости автоматически принимал идентификатор по значению самого поля.

Вы должны:

  1. Получите запись Title сначала title.
  2. Установите title на ClientMaster, если он был выбран ... не делайте ничего другого и разрешите каскаду сохранить это значение.
  3. Используйте merge вместо persist на объекте ClientMaster:

    cmrepository.merge(cm);

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