加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

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

发布时间:2020-12-15 02:59:41 所属栏目:Java 来源:网络整理
导读:我有这两个简单的实体Something and Property. Something实体与Property具有多对一关系,因此当我创建一个新的Something行时,我会分配一个现有的Property. 东西: @Entity@Table(name = "something")public class Something implements Serializable { privat
我有这两个简单的实体Something and 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;
    }
}

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

{
  "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);

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

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读