简体   繁体   中英

JPA return full foreign key entity on Insert/Update

My goal is to be able to insert the below object with the user passing in the relevant data and the id of the foreign key, and return back to the user a full object that contains the full foreign key object as well, not just the foreign key 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;
}

I was trying with the above and it inserts but it only returns the foreignObjectId on insert and not the entire foreign object.

I tried the below to get it to work but no luck.

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

and also tried

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

I'm not sure if there is something in my domain object I need to change or if I need to change my create method in some way.

Current output is:

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

Expected output is:

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

The problem is the following where you are corrupting your domain model to try and make it fit some front-end concern:

@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;

You are never setting the relationship but only the integer field.

This will not work as a call to EntityManager#persist (via myObjectRepository.save) simply takes the existing object and makes it persistent ie nothing is going to trigger setting the reference to ForeignObject.

@Transactional
public MyObject create(MyObject myObject) {

    //createdMyObject and  myObject are same instance  

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

This will not work as the same instance (ie the one you created without the relationship set) will simply be retrieved from the Hibernate's first level cache:

   @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());
    }

You can probable get method 2 to work by doing the following however the correct solution is to remove the Integer field and have the relationship set correctly. A Spring MVC controller should automatically set the reference from the ID on POST/PUT request with {... "foreignObject" : 3 ...}

   @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());
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM