java – 保存后刷新并获取实体(JPA / Spring Data / Hibernate)

前端之家收集整理的这篇文章主要介绍了java – 保存后刷新并获取实体(JPA / Spring Data / Hibernate)前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我有这两个简单的实体Something and Property.
Something实体与Property具有多对一关系,因此当我创建一个新的Something行时,我会分配一个现有的Property.

东西:

  1. @Entity
  2. @Table(name = "something")
  3. public class Something implements Serializable {
  4.  
  5. private static final long serialVersionUID = 1L;
  6.  
  7. @Id
  8. @GeneratedValue(strategy = GenerationType.IDENTITY)
  9. private Long id;
  10.  
  11. @Column(name = "name")
  12. private String name;
  13.  
  14. @Column(name = "owner")
  15. private String owner;
  16.  
  17. @ManyToOne
  18. private Property property;
  19.  
  20. // getters and setters
  21.  
  22. @Override
  23. public String toString() {
  24. return "Something{" +
  25. "id=" + getId() +
  26. ",name='" + getName() + "'" +
  27. ",owner='" + getOwner() + "'" +
  28. ",property=" + getProperty() +
  29. "}";
  30. }

属性

  1. @Entity
  2. @Table(name = "property")
  3. public class Property implements Serializable {
  4.  
  5. private static final long serialVersionUID = 1L;
  6.  
  7. @Id
  8. @GeneratedValue(strategy = GenerationType.IDENTITY)
  9. private Long id;
  10.  
  11. @Column(name = "shape")
  12. private String shape;
  13.  
  14. @Column(name = "color")
  15. private String color;
  16.  
  17. @Column(name = "dimension")
  18. private Integer dimension;
  19.  
  20. // getters and setters
  21.  
  22. @Override
  23. public String toString() {
  24. return "Property{" +
  25. "id=" + getId() +
  26. ",shape='" + getShape() + "'" +
  27. ",color='" + getColor() + "'" +
  28. ",dimension='" + getDimension() + "'" +
  29. "}";
  30. }
  31. }

这是SomethingRepository(Spring):

  1. @SuppressWarnings("unused")
  2. @Repository
  3. public interface SomethingRepository extends JpaRepository<Something,Long> {
  4.  
  5. }

通过REST控制器和JSON,我想创建一个新的东西:

  1. @RestController
  2. @RequestMapping("/api")
  3. public class SomethingResource {
  4.  
  5. private final SomethingRepository somethingRepository;
  6.  
  7. public SomethingResource(SomethingRepository somethingRepository) {
  8. this.somethingRepository = somethingRepository;
  9. }
  10.  
  11. @PostMapping("/somethings")
  12. public Something createSomething(@RequestBody Something something) throws URISyntaxException {
  13. Something result = somethingRepository.save(something);
  14. return result;
  15. }
  16. }

这是输入中的JSON(属性id 1是数据库中的现有行):

  1. {
  2. "name": "MyName","owner": "MySelf","property": {
  3. "id": 1
  4. }

}

问题是:在方法.save(something)之后,变量result包含持久化实体,但没有field属性字段,验证(它们为null):

输出JSON:

  1. {
  2. "id": 1,"name": "MyName","property": {
  3. "id": 1,"shape": null,"color": null,"dimension": null
  4. }
  5. }

我希望在保存操作后验证/返回它们.

解决这个问题,我必须在REST控制器中注入/声明EntityManager,并调用方法EntityManager.refresh(something)(或者我必须调用.findOne(something.getId())方法来获得完整的持久化实体):

  1. @RestController
  2. @RequestMapping("/api")
  3. @Transactional
  4. public class SomethingResource {
  5.  
  6. private final SomethingRepository somethingRepository;
  7.  
  8. private final EntityManager em;
  9.  
  10. public SomethingResource(SomethingRepository somethingRepository,EntityManager em) {
  11. this.somethingRepository = somethingRepository;
  12. this.em = em;
  13. }
  14.  
  15. @PostMapping("/somethings")
  16. public Something createSomething(@RequestBody Something something) throws URISyntaxException {
  17. Something result = somethingRepository.save(something);
  18. em.refresh(result);
  19. return result;
  20. }
  21. }

通过这种解决方法,我得到了预期的保存entith(使用正确的JSON):

  1. {
  2. "id": 4,"shape": "Rectangle","color": "Red","dimension": 50
  3. }
  4. }

是否有自动方法/注释,使用JPA或Spring或Hibernate,以获得“完整”持久化实体?

我想避免在每个REST或Service类中声明EntityManager,或者我希望每次我想要新刷新的持久化实体时都避免调用.findOne(Long)方法.

非常感谢,
安德里亚

解决方法

这还不够:
  1. Something result = somethingRepository.save(something);

您需要手动合并传入的实体:

  1. Something dbSomething = somethingRepository.findOne(
  2. Something.class,something.getId()
  3. );
  4. dbSomething.setName(something.getName());
  5. dbSomething.setOwner(something.getOwner());
  6.  
  7. somethingRepository.save(dbSomething);

由于属性属性使用默认值FetchType.EAGER,因此实体应初始化属性属性.

但是,从REST控制器调用存储库两次是很奇怪的.你应该有一个服务层来完成@Transactional服务方法中的所有操作.这样,您不需要重新保存实体,因为它已经被管理.

  1. @Transactional
  2. public Something mergeSomething(Something something) {
  3. Something dbSomething = somethingRepository.findOne(
  4. Something.class,something.getId()
  5. );
  6. dbSomething.setName(something.getName());
  7. dbSomething.setOwner(something.getOwner());
  8.  
  9. return dbSomething;
  10. }

现在,您需要仔细合并您发送的每个属性.在您的情况下,如果您为属性发送null,您应该决定是否应该取消@ManyToOne引用.因此,它取决于您当前的应用程序业务逻辑要求.

更新

如果您确定始终发送回先前提取的同一实体,则可以使用合并.

  1. em.refresh(result);

但是您的属性属性只是一个id,而不是一个实际的子实体,因此您必须自己在Service层中解决它.

猜你在找的Java相关文章