我有这两个简单的实体Something and Property.
Something实体与Property具有多对一关系,因此当我创建一个新的Something行时,我会分配一个现有的Property.
Something实体与Property具有多对一关系,因此当我创建一个新的Something行时,我会分配一个现有的Property.
东西:
- @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() +
- "}";
- }
属性:
- @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() + "'" +
- "}";
- }
- }
这是SomethingRepository(Spring):
- @SuppressWarnings("unused")
- @Repository
- public interface SomethingRepository extends JpaRepository<Something,Long> {
- }
通过REST控制器和JSON,我想创建一个新的东西:
- @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;
- }
- }
- {
- "name": "MyName","owner": "MySelf","property": {
- "id": 1
- }
}
问题是:在方法.save(something)之后,变量result包含持久化实体,但没有field属性字段,验证(它们为null):
输出JSON:
- {
- "id": 1,"name": "MyName","property": {
- "id": 1,"shape": null,"color": null,"dimension": null
- }
- }
我希望在保存操作后验证/返回它们.
要解决这个问题,我必须在REST控制器中注入/声明EntityManager,并调用方法EntityManager.refresh(something)(或者我必须调用.findOne(something.getId())方法来获得完整的持久化实体):
- @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;
- }
- }
通过这种解决方法,我得到了预期的保存entith(使用正确的JSON):
- {
- "id": 4,"shape": "Rectangle","color": "Red","dimension": 50
- }
- }
是否有自动方法/注释,使用JPA或Spring或Hibernate,以获得“完整”持久化实体?
我想避免在每个REST或Service类中声明EntityManager,或者我希望每次我想要新刷新的持久化实体时都避免调用.findOne(Long)方法.
非常感谢,
安德里亚
解决方法
这还不够:
- Something result = somethingRepository.save(something);
您需要手动合并传入的实体:
- Something dbSomething = somethingRepository.findOne(
- Something.class,something.getId()
- );
- dbSomething.setName(something.getName());
- dbSomething.setOwner(something.getOwner());
- somethingRepository.save(dbSomething);
由于属性属性使用默认值FetchType.EAGER
,因此实体应初始化属性属性.
但是,从REST控制器调用存储库两次是很奇怪的.你应该有一个服务层来完成@Transactional服务方法中的所有操作.这样,您不需要重新保存实体,因为它已经被管理.
- @Transactional
- public Something mergeSomething(Something something) {
- Something dbSomething = somethingRepository.findOne(
- Something.class,something.getId()
- );
- dbSomething.setName(something.getName());
- dbSomething.setOwner(something.getOwner());
- return dbSomething;
- }
现在,您需要仔细合并您发送的每个属性.在您的情况下,如果您为属性发送null,您应该决定是否应该取消@ManyToOne引用.因此,它取决于您当前的应用程序业务逻辑要求.
更新
如果您确定始终发送回先前提取的同一实体,则可以使用合并.
- em.refresh(result);