JPA在插入/更新时返回完整的外键实体

时间:2019-07-10 17:59:11

标签: java mysql hibernate jpa

我的目标是能够在用户传递相关数据和外键ID的情况下插入以下对象,然后将还包含完整外键对象的完整对象返回给用户,而不是只是外键ID。

@Data
@Entity
@EqualsAndHashCode(callSuper = false)
@Table(name = MY_OBJECT_TABLE)
public class MyObject {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "MY_OBJECT_ID", unique = true, nullable = false)
    private Integer myObjectId;

    @ManyToOne(targetEntity = ForeignObject.class, fetch = FetchType.EAGER)
    @JoinColumn(name = "FOREIGN_OBJECT_ID", referencedColumnName = "FOREIGN_OBJECT_ID", nullable = false, insertable = false, updatable = false)
    private ForeignObject foreignObject;

    @Column(name = "FOREIGN_OBJECT_ID")
    private Integer foreignObjectId;

    @Column(name = "RANDOM_FIELD", nullable = false)
    @NotNull
    private Boolean randomField;
}

我尝试使用上面的方法,它会插入,但它只会在插入时返回foreignObjectId,而不是整个异物。

我尝试了以下方法使其正常运行,但没有运气。

    @Transactional
    public MyObject create(MyObject myObject) {
        MyObject createdMyObject = this.myObjectRepository.save(myObject);
        return createdMyObject;
    }

也尝试过

    @Transactional
    public MyObject create(MyObject myObject) {
        MyObject createdMyObject = this.myObjectRepository.save(myObject);
        return this.myObjectRepository.findById(createdMyObject.getMyObjectId());
    }

我不确定我的域对象中是否需要更改或是否需要以某种方式更改创建方法。

当前输出为:

{
  "myObjectId": 1,
  "foreignObject": null,
  "foreignObjectId": 3,
  "randomField": true
}

预期输出为:

{
  "myObjectId": 1,
  "foreignObject": {
    "foreignObjectId": 3,
  },
  "foreignObjectId": 3, // I don't care if this field stays here or not
  "randomField": true
}

1 个答案:

答案 0 :(得分:2)

以下是问题所在,您正在破坏域模型以尝试使其适合某些前端问题:

@ManyToOne(targetEntity = ForeignObject.class, fetch = FetchType.EAGER)
@JoinColumn(name = "FOREIGN_OBJECT_ID", referencedColumnName = "FOREIGN_OBJECT_ID", 
                       nullable = false, insertable = false, updatable = false)
private ForeignObject foreignObject;

@Column(name = "FOREIGN_OBJECT_ID")
private Integer foreignObjectId;

您永远不会设置关系,而只设置整数字段。

这不会像调用EntityManager#persist(通过myObjectRepository.save)那样简单地获取现有对象并使之持久化,即不会触发设置对ForeignObject的引用。

@Transactional
public MyObject create(MyObject myObject) {

    //createdMyObject and  myObject are same instance  

    MyObject createdMyObject = this.myObjectRepository.save(myObject);
    return createdMyObject;
}

这将无法与同一个实例(即您创建的没有关联集的实例)一起简单地从Hibernate的一级缓存中检索:

   @Transactional
    public MyObject create(MyObject myObject) {
        //createdMyObject, myObject and (due to 1st level cache) 
        //object returned from query are same 

        MyObject createdMyObject = this.myObjectRepository.save(myObject);
        return this.myObjectRepository.findById(createdMyObject.getMyObjectId());
    }

您可以通过执行以下使方法2起作用,但是正确的解决方案是删除Integer字段并正确设置关系。 Spring MVC控制器应使用{... "foreignObject" : 3 ...}

根据POST / PUT请求上的ID自动设置引用。
   @PersistenceContect
   EntityManager em;

   @Transactional
    public MyObject create(MyObject myObject) {
        this.myObjectRepository.saveAndFlush(myObject);
        em.clear(); //force reload from database
        return this.myObjectRepository.findById(createdMyObject.getMyObjectId());
    }