Refresh and fetch an entity after save (JPA/Spring Data/Hibernate)

Viewed 89217

I've these two simple entities Something and Property. The Something entity has a many-to-one relationship to Property, so when I create a new Something row, I assign an existing Property.

Something:

@Entity
@Table(name = "something")
public class Something implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

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

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

    @ManyToOne
    private Property property;

    // getters and setters

    @Override
    public String toString() {
        return "Something{" +
            "id=" + getId() +
            ", name='" + getName() + "'" +
            ", owner='" + getOwner() + "'" +
            ", property=" + getProperty() +
            "}";
    }

Property:

@Entity
@Table(name = "property")
public class Property implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

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

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

    @Column(name = "dimension")
    private Integer dimension;

    // getters and setters

    @Override
    public String toString() {
        return "Property{" +
            "id=" + getId() +
            ", shape='" + getShape() + "'" +
            ", color='" + getColor() + "'" +
            ", dimension='" + getDimension() + "'" +
            "}";
    }
}

This is the SomethingRepository (Spring):

@SuppressWarnings("unused")
@Repository
public interface SomethingRepository extends JpaRepository<Something,Long> {
    
}

Through a REST controller and a JSON, I want to create a new Something:

@RestController
@RequestMapping("/api")
public class SomethingResource {

    private final SomethingRepository somethingRepository;

    public SomethingResource(SomethingRepository somethingRepository) {
        this.somethingRepository = somethingRepository;
    }

    @PostMapping("/somethings")
    public Something createSomething(@RequestBody Something something) throws URISyntaxException {
        Something result = somethingRepository.save(something);
        return result;
    }
}

This is the JSON in input (the property id 1 is an existing row in the database):

{
  "name": "MyName",
  "owner": "MySelf",
  "property": {
    "id": 1
  }

}

The problem is: after the method .save(something), the variable result contains the persisted entity, but without the fields of field property, validated (they are null):

Output JSON:

{
  "id": 1,
  "name": "MyName",
  "owner": "MySelf",
  "property": {
    "id": 1,
    "shape": null,
    "color": null,
    "dimension": null
  }
}

I expect that they are validated/returned after the save operation.

To workaround this, I have to inject/declare the EntityManager in the REST controller, and call the method EntityManager.refresh(something) (or I have to call a .findOne(something.getId()) method to have the complete persisted entity):

@RestController
@RequestMapping("/api")
@Transactional
public class SomethingResource {

    private final SomethingRepository somethingRepository;
    
    private final EntityManager em;

    public SomethingResource(SomethingRepository somethingRepository, EntityManager em) {
        this.somethingRepository = somethingRepository;
        this.em = em;
    }

    @PostMapping("/somethings")
    public Something createSomething(@RequestBody Something something) throws URISyntaxException {
        Something result = somethingRepository.save(something);
        em.refresh(result);
        return result;
    }
}

With this workaround, I've the expected saved entith (with a correct JSON):

{
  "id": 4,
  "name": "MyName",
  "owner": "MySelf",
  "property": {
    "id": 1,
    "shape": "Rectangle",
    "color": "Red",
    "dimension": 50
  }
}

Is there an automatic method/annotation, with JPA or Spring or Hibernate, in order to have the "complete" persisted entity?

I would like to avoid to declare the EntityManager in every REST or Service class, or I want avoid to call the .findOne(Long) method everytime I want the new refreshed persisted entity.

5 Answers

In Spring Boot JpaRepository:

If our modifying query changes entities contained in the persistence context, then this context becomes outdated.

In order to fetch the entities from the database with latest record.

Use @Modifying(clearAutomatically = true)

@Modifying annotation has clearAutomatically attribute which defines whether it should clear the underlying persistence context after executing the modifying query.

Example:

@Modifying(clearAutomatically = true)
@Query("UPDATE NetworkEntity n SET n.network_status = :network_status WHERE n.network_id = :network_id")
        int expireNetwork(@Param("network_id") Integer network_id,  @Param("network_status") String network_status);

I would replace the property with a proxy generated using session.load

        something.setProperty(session.load(Property.class, something.getProperty().getId()))
        Something result = somethingRepository.save(something);
        return result;

Now the result will have the entire property object loaded from the db

Related