Search code examples
spring-bootspring-data-jpaspring-data

The result entity after calling JpaRepository.getById() does not contain values for fields with @JoinColumn after calling JpaRepository.saveAndFlush()


When I save an entity that has a @JoinColumn field that references another entity, it is saved correctly as expected by calling saveAndFlush(). Now, I want to be able to return this entity along with its related entities back to the user. I assumed that calling getById() with the ID of the newly saved entity will also retrieve @JoinColumn values in the returned entity, however, the related entity of the returned entity contains the exact same values as the related entity that used in saveAndFlush(). I have made example code to demonstrate what I'm talking about.

I send request: GET http://localhost:8080 and receive as response:

{
  "id": 3,
  "name": "tests",
  "related": {
    "id": 3,
    "name": null
  }
}

My goal is to have the same request return the following response:

{
  "id": 3,
  "name": "tests",
  "related": {
    "id": 3,
    "name": "test"
  }
}

Where the related contains name along with id which was specified in the saveAndFlush().

Controller.java

import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequiredArgsConstructor
public class Controller {

    private final ObjectRepository oRepo;
    private final RelatedObjectRepository coRepo;

    @GetMapping
    private Object test() {
        // imagine as if this entity is already present in the database before this request is handled, this line is only for context.
        RelatedObject co = coRepo.saveAndFlush(new RelatedObject(null, "test"));
        
        // create an instance of RelatedObject to contain the value for the related_id foreign key column.
        RelatedObject nco = new RelatedObject(co.getId(), null);
        // create Object and save it along with the referenced RelatedObject.
        Object o = oRepo.saveAndFlush(new Object(null, "tests", nco));

        // I expected all values of 'co' object to be contained in the result here in the @JoinColumn field 'related' of Object, instead, only 'id' is present like the 'nco' object
        return oRepo.getById(o.getId());
    }
}

Object.java

import lombok.*;

import javax.persistence.*;

@Table(name = "object")
@Entity
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class Object {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", nullable = false)
    private Long id;

    @Column(name = "name", length = 100)
    private String name;

    @ManyToOne
    @JoinColumn(name = "related_id")
    private RelatedObject related;

}

RelatedObject.java

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import javax.persistence.*;

@Table(name = "related_object")
@Entity
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class RelatedObject {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "Id", nullable = false)
    private Long id;

    @Column(name = "name", length = 100)
    private String name;
}

ObjectRepository.java

import org.springframework.data.jpa.repository.JpaRepository;

public interface ObjectRepository extends JpaRepository<Object, Long> {
}

RelatedObjectRepository.java

import org.springframework.data.jpa.repository.JpaRepository;

public interface RelatedObjectRepository extends JpaRepository<RelatedObject, Long> {
}

SpringPlayGroundApplication.java

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringPlayGroundApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringPlayGroundApplication.class, args);
    }

}

Solution

  • Alright, I figured out what I needed.

    Associated entities needed to cascade refresh, for example:

    @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.REFRESH)
    @JoinColumn(name = "parent_id")
    private Category parent;