Update entity collection field with Hibernate

Viewed 165

I'd like to update a collection field List<Bar> bars in JPA entity Foo, but without changing the original one - just set the updatedBars to bars field before save. But my code isn't working, probably because the updatedBars are not persistent despite the fact that some Bar objects are from original collection. Any suggestions, please.

P.S. This way of updating collection seems easier to me, because I can just populate an updatedBars in stream copying and updating, creating, and just ignoring values from original collection instead of performing separate operations like remove, update, add on the original collection.

Here is my code example:

@Getter
@Setter
@Entity
@Table(name = "foo")
public class Foo {
    
    @Id
    @Column(name = "id")
    private Long id;
    
    @JoinColumn(name = "foo_id")
    @OneToMany(fetch = FetchType.LAZY, orphanRemoval = true, cascade = CascadeType.ALL)
    private List<Bar> bars;
}
@Getter
@Setter
@Entity
@Table(name = "bar")
public class Bar {
    
    @Id
    @Column(name = "id")
    private Long id;
    
    @Column(name = "foo_id")
    private Long fooId;

    @Column(name = "value")
    private Long value;
}
@Transactional
public void refresh(Long fooId){
    Foo foo = fooRepository.find(fooId);
    List<Bar> updatedBars = getUpdatedBars(foo.getBars());
    foo.setBars(updatedBars);
}

private List<Bar> getUpdatedBars(List<Bar> originalBars) {
    //do any staff to return new list of Bars, not changing the original one
    //some items are removed, some updated (same entity from original list, with changed value field), some added (entities without ids)
}

UPDATE: Updating the content of original collection also did't work.

@Transactional
public void refresh(Long fooId){
    Foo foo = fooRepository.find(fooId);
    List<Bar> originalBars = foo.getBars();
    List<Bar> updatedBars = getUpdatedBars(originalBars);
    originalBars.clear();
    originalBars.addAll(updatedBars);
}

2 Answers

I don't know what without changing the original one should mean, but you could just detach the entity right after loading so that the database state is not updated when you change the collection.

What you are describing is a deep copy. If the type parameter of the list is a primitive, there are a few options but if it's a complex object such as the case an option is iterating source list and creating new objects in destination.

public void copy(List<Bar> dest, List<Bar> source){
    dest.clear();
    for (int i = 0; i < source.size(); i++) {
        dest.add(new Bar(source.get(i)));
    }
}

There are other options such as serializing and deserializing using a library like Jackson or Gson. That would create a new list of objects without need to do it "manually". ref: How do you make a deep copy of an object?

Related