JPA возвращает полный объект внешнего ключа при вставке / обновлении - PullRequest
1 голос
/ 10 июля 2019

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

@Data
@Entity
@EqualsAndHashCode(callSuper = false)
@Table(name = MY_OBJECT_TABLE)
public class MyObject {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "MY_OBJECT_ID", unique = true, nullable = false)
    private Integer myObjectId;

    @ManyToOne(targetEntity = ForeignObject.class, fetch = FetchType.EAGER)
    @JoinColumn(name = "FOREIGN_OBJECT_ID", referencedColumnName = "FOREIGN_OBJECT_ID", nullable = false, insertable = false, updatable = false)
    private ForeignObject foreignObject;

    @Column(name = "FOREIGN_OBJECT_ID")
    private Integer foreignObjectId;

    @Column(name = "RANDOM_FIELD", nullable = false)
    @NotNull
    private Boolean randomField;
}

Я пытался с вышеупомянутым, и он вставляет, но он возвращает только externalObjectId при вставке, а не весь внешний объект.

Я пробовал ниже, чтобызаставить его работать, но не повезло.

    @Transactional
    public MyObject create(MyObject myObject) {
        MyObject createdMyObject = this.myObjectRepository.save(myObject);
        return createdMyObject;
    }

, а также попытался

    @Transactional
    public MyObject create(MyObject myObject) {
        MyObject createdMyObject = this.myObjectRepository.save(myObject);
        return this.myObjectRepository.findById(createdMyObject.getMyObjectId());
    }

Я не уверен, есть ли что-то в моем доменном объекте, который мне нужно изменить, или если мне нужночтобы каким-то образом изменить мой метод создания.

Текущий вывод:

{
  "myObjectId": 1,
  "foreignObject": null,
  "foreignObjectId": 3,
  "randomField": true
}

Ожидаемый вывод:

{
  "myObjectId": 1,
  "foreignObject": {
    "foreignObjectId": 3,
  },
  "foreignObjectId": 3, // I don't care if this field stays here or not
  "randomField": true
}

1 Ответ

2 голосов
/ 11 июля 2019

Проблема заключается в следующем, когда вы портите модель своего домена, пытаясь привести ее в соответствие с какой-либо внешней задачей:

@ManyToOne(targetEntity = ForeignObject.class, fetch = FetchType.EAGER)
@JoinColumn(name = "FOREIGN_OBJECT_ID", referencedColumnName = "FOREIGN_OBJECT_ID", 
                       nullable = false, insertable = false, updatable = false)
private ForeignObject foreignObject;

@Column(name = "FOREIGN_OBJECT_ID")
private Integer foreignObjectId;

Вы никогда не устанавливаете отношение, а только целочисленное поле.

Это не будет работать, так как вызов EntityManager#persist (через myObjectRepository.save) просто берет существующий объект и делает его постоянным, т. Е. Ничто не приведет к установке ссылки на ForeignObject.

@Transactional
public MyObject create(MyObject myObject) {

    //createdMyObject and  myObject are same instance  

    MyObject createdMyObject = this.myObjectRepository.save(myObject);
    return createdMyObject;
}

Это не будет работать, так как тот же экземпляр (т. Е. Тот, который вы создали без набора отношений) будет просто извлечен из кэша первого уровня Hibernate:

   @Transactional
    public MyObject create(MyObject myObject) {
        //createdMyObject, myObject and (due to 1st level cache) 
        //object returned from query are same 

        MyObject createdMyObject = this.myObjectRepository.save(myObject);
        return this.myObjectRepository.findById(createdMyObject.getMyObjectId());
    }

Вероятно, заставить метод 2 работать, выполнивследующий однако правильное решение состоит в том, чтобы удалить поле Integer и правильно установить отношения.Контроллер Spring MVC должен автоматически установить ссылку от ID по запросу POST / PUT с {... "foreignObject" : 3 ...}

   @PersistenceContect
   EntityManager em;

   @Transactional
    public MyObject create(MyObject myObject) {
        this.myObjectRepository.saveAndFlush(myObject);
        em.clear(); //force reload from database
        return this.myObjectRepository.findById(createdMyObject.getMyObjectId());
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...