保存后刷新并获取一个实体(JPA / Spring Data / Hibernate) [英] Refresh and fetch an entity after save (JPA/Spring Data/Hibernate)

查看:94
本文介绍了保存后刷新并获取一个实体(JPA / Spring Data / Hibernate)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两个简单的实体 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长ID;

@Column(name =name)
私有字符串名称;

@Column(name =owner)
private String owner;

@ManyToOne
私有财产;

// getters and setters

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

属性:

  @Entity 
@Table(name =property)
public class Property实现Serializable {

private static final long serialVersionUID = 1L;

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private长ID;

@Column(name =shape)
私人字符串形状;

@Column(name =color)
private String color;

@Column(name =dimension)
private Integer dimension;

// getters and setters

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


$ / code $ / pre

这是 SomethingRepository (Spring):
$ b $ pre $ @SuppressWarnings(unused)
@Repository
public interface SomethingRepository扩展JpaRepository< Something,Long> {

}

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

  @RestController 
@RequestMapping (/ api)
公共类SomethingResource {

private final SomethingRepository somethingRepository;

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

$ b @PostMapping(/ somethings)
public Something createSomething(@RequestBody Something something)throws URISyntaxException {
Something result = somethingRepository.save(something) ;
返回结果;




$ b这是输入中的JSON(<$ c




$ b $ $ $ $
name:MyName,
owner:MySelf,
property:{
id :1
}

}

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

输出JSON:

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

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



为了解决这个问题,我必须注入/声明 Enti tyManager 在REST控制器中,并调用方法 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;

$ b @PostMapping(/ somethings)
public Something createSomething(@RequestBody Something something)throws URISyntaxException {
Something result = somethingRepository.save(something) ;
em.refresh(result);
返回结果;


$ / code $ / pre

有了这个解决方法,我有了预期的保存头(使用正确的JSON):

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

是否有自动方法/注释,使用JPA或Spring或Hibernate,以便拥有完整持久实体?



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



非常感谢,
Andrea

解决方案

这还不够:

  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 ,实体应该已经初始化属性属性。



但是,调用Repository两次来自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 。因此,这取决于您当前的应用程序业务逻辑要求。



更新



如果您确定始终发送返回先前提取的实体,您可以使用 merge

  em.refresh(结果); 

但是您的属性属性只是一个id ,而不是实际的子实体,所以你必须在服务层自己解决。


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.

Thanks a lot, Andrea

解决方案

That's not enough:

Something result = somethingRepository.save(something);

You need to manually merge the incoming entity:

Something dbSomething = somethingRepository.findOne(
    Something.class, something.getId()
);
dbSomething.setName(something.getName());
dbSomething.setOwner(something.getOwner());

somethingRepository.save(dbSomething);

Since the property attribute is using the default FetchType.EAGER, the entity should have the property attribute initialized.

But, that's strange to call the Repository twice from the REST controller. You should have a Service layer that does all that in a @Transactional service method. That way, you don't need to resave the entity since it's 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 every property you sent. In your case, if you send null for property you should decide whether you should nullify the @ManyToOne reference or not. So, it depends on your current application business logic requirements.

Update

If you make sure you always send back the same entity you previously fetched, you could just use merge.

em.refresh(result);

But your property attribute is just an id, and not an actual child entity, so you have to resolve that yourself in the Service layer.

这篇关于保存后刷新并获取一个实体(JPA / Spring Data / Hibernate)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆