1

I have following two entities in OneToOne relationship.

@Entity
@Audited
public class Parent implements Serializable {

    @Id
    @GeneratedValue(generator = "system-uuid")
    @GenericGenerator(name = "system-uuid", strategy = "uuid2")
    @Size(max = 36)
    @Column(length = 36)
    private String id;

    @NotNull
    private String createdUser;

    @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
    @Temporal(TemporalType.TIMESTAMP)
    @NotNull
    private Date createdDate;

    private String modifiedUser;

    @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
    @Temporal(TemporalType.TIMESTAMP)
    private Date modifiedDate;

    @OneToOne(targetEntity = Child.class, optional = false, fetch = FetchType.EAGER, cascade = { CascadeType.ALL }, orphanRemoval = true)
    @Fetch(FetchMode.JOIN)
    private Child child = new Child();

    @PrePersist
    public void prePersist() {

        createdDate = new Date();
        createdUser = "SampleUser";

    }

    @PreUpdate
    public void preUpdate() {

        modifiedDate = new Date();
        modifiedUser = "SampleUser";

    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getCreatedUser() {
        return createdUser;
    }

    public void setCreatedUser(String createdUser) {
        this.createdUser = createdUser;
    }

    public Date getCreatedDate() {
        return createdDate;
    }

    public void setCreatedDate(Date createdDate) {
        this.createdDate = createdDate;
    }

    public String getModifiedUser() {
        return modifiedUser;
    }

    public void setModifiedUser(String modifiedUser) {
        this.modifiedUser = modifiedUser;
    }

    public Date getModifiedDate() {
        return modifiedDate;
    }

    public void setModifiedDate(Date modifiedDate) {
        this.modifiedDate = modifiedDate;
    }

    public Child getChild() {
        return child;
    }

    public void setChild(Child child) {
        this.child = child;
    }
}
@Entity
@Audited
public class Child implements Serializable {

    @Id
    @GeneratedValue(generator = "system-uuid")
    @GenericGenerator(name = "system-uuid", strategy = "uuid2")
    @Size(max = 36)
    @Column(length = 36)
    private String id;

    private String sampleField;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getSampleField() {
        return sampleField;
    }

    public void setSampleField(String sampleField) {
        this.sampleField = sampleField;
    }
}

Now I need to update the parents modified (date & user) fields. If i change only the field (sampleField) in the child then the modified fields are not updated in the parent.

I found following two statements and if I understand it correctly then its not a good idea to change the parent in lifecycle events (Interceptor, EventListener, Callbacks) of the child.

Statement 1 Statement 2

What is a save way to address my problem?

Update

I found this way from vlad: How to increment the parent entity version. But I'm not sure if this way is safe. Life cycle events are also used.

user3612610
  • 233
  • 4
  • 18

1 Answers1

0

I can only offer you a workaround, as I don't think what you want to achieve is doable out of the box with Hibernate or any other JPA provider.

You can encapsulate the Child completely, and with a bi-directional reference, you can make sure that the modifiedDate is dirtied when necessary. A model similar to this should suffice:

@Entity
@Audited
public class Parent implements Serializable {

    @Id
    @GeneratedValue(generator = "system-uuid")
    @GenericGenerator(name = "system-uuid", strategy = "uuid2")
    @Size(max = 36)
    @Column(length = 36)
    private String id;

    @NotNull
    private String createdUser;

    @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
    @Temporal(TemporalType.TIMESTAMP)
    @NotNull
    private Date createdDate;

    private String modifiedUser;

    @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
    @Temporal(TemporalType.TIMESTAMP)
    private Date modifiedDate;

    @OneToOne(targetEntity = Child.class, optional = false, fetch = FetchType.EAGER, cascade = { CascadeType.ALL }, orphanRemoval = true)
    @Fetch(FetchMode.JOIN)
    private Child child;

    public Parent() {
        child = new Child(this);
    }

    @PrePersist
    public void prePersist() {
        createdDate = modifiedDate = new Date();
        createdUser = modifiedUser = "SampleUser";
        
    }

    @PreUpdate
    public void preUpdate() {
        modifiedDate = new Date();
        modifiedUser = "SampleUser";
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getCreatedUser() {
        return createdUser;
    }

    public void setCreatedUser(String createdUser) {
        this.createdUser = createdUser;
    }

    public Date getCreatedDate() {
        return createdDate;
    }

    public void setCreatedDate(Date createdDate) {
        this.createdDate = createdDate;
    }

    public String getModifiedUser() {
        return modifiedUser;
    }

    public void setModifiedUser(String modifiedUser) {
        this.modifiedUser = modifiedUser;
    }

    public Date getModifiedDate() {
        return modifiedDate;
    }

    public void setModifiedDate(Date modifiedDate) {
        this.modifiedDate = modifiedDate;
    }

    public Child getChild() {
        return child;
    }

    // Note that I removed the setter
}
@Entity
@Audited
public class Child implements Serializable {

    @Id
    @GeneratedValue(generator = "system-uuid")
    @GenericGenerator(name = "system-uuid", strategy = "uuid2")
    @Size(max = 36)
    @Column(length = 36)
    private String id;

    private String sampleField;

    @OneToOne(mappedBy = "child")
    private Parent parent;

    public Child() {}

    public Child(Parent parent) {
        this.parent = parent;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getSampleField() {
        return sampleField;
    }

    public void setSampleField(String sampleField) {
        if (parent != null && !Objects.equals(this.sampleField, sampleField)) {
            parent.setModifiedDate(null);
        }
        this.sampleField = sampleField;
    }
}
Christian Beikov
  • 15,141
  • 2
  • 32
  • 58