Java – refresh and get entities after saving (JPA / spring data / Hibernate)
I have these two simple entities something and property
Things:
@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() + "}"; }
Properties:
@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 something repository (spring):
@SuppressWarnings("unused") @Repository public interface SomethingRepository extends JpaRepository<Something,Long> { }
Through rest controller and JSON, I want to create a new thing:
@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 JSON in the input (attribute ID 1 is an existing row in the database):
{ "name": "MyName","owner": "MySelf","property": { "id": 1 }
}
The problem is: in the method After saving (something), the variable result contains the persistent entity, but there is no field attribute field. Verify (they are null):
Output JSON:
{ "id": 1,"name": "MyName","property": { "id": 1,"shape": null,"color": null,"dimension": null } }
I want to validate / return them after saving operations
To solve this problem, I must inject / declare entitymanager in the rest controller and call the method entitymanager Refresh (something) (or I must call the. Findone (something. Getid()) method to get the complete persistent 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; } }
Through this solution, I get the expected save entith (using the correct JSON):
{ "id": 4,"shape": "Rectangle","color": "Red","dimension": 50 } }
Are there automatic methods / annotations that use JPA or spring or hibernate to obtain "complete" persistent entities?
I want to avoid declaring entitymanager in every rest or service class, or I want to avoid calling every time I want a newly refreshed persistent entity Findone (long) method
Thank you very much, Andrea
Solution
This is not enough:
Something result = somethingRepository.save(something);
You need to merge the incoming entities manually:
Something dbSomething = somethingRepository.findOne( Something.class,something.getId() ); dbSomething.setName(something.getName()); dbSomething.setOwner(something.getOwner()); somethingRepository.save(dbSomething);
Because the property uses the default value fetchtype Eager, so the entity should initialize the attribute
However, it is strange to call the repository twice from the rest controller You should have a service layer to complete all operations in @ transactional service methods In this way, you do not need to resave the entity because it is already managed
@Transactional public Something mergeSomething(Something something) { Something dbSomething = somethingRepository.findOne( Something.class,something.getId() ); dbSomething.setName(something.getName()); dbSomething.setOwner(something.getOwner()); return dbSomething; }
Now, you need to carefully merge each attribute you send In your case, if you send null for a property, you should decide whether you should cancel the @ manytoone reference Therefore, it depends on your current application business logic requirements
to update
Use merge if you are sure to always send back the same entity that was previously extracted
em.refresh(result);
However, your attribute is only an ID, not an actual sub entity, so you must solve it yourself in the service layer