0

I think it's very common problem with saving new entity with exisitng entities (@ManyToMany relation)

Place model

@Entity
@Table(name = "places")
public class Place implements Serializable {

    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Id
    @Getter
    private Long id;

@Getter
    @Setter
    @ManyToMany(mappedBy = "places", cascade = {CascadeType.MERGE, CascadeType.REMOVE, CascadeType.REFRESH})
    private Set<Tag> tags = new HashSet<>();
}

Tag model

@Entity
@Table(name = "tags")
public class Tag implements Serializable {

    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Id
    @Getter
    private Long id;

    @Getter
    @Setter
    @ManyToMany(cascade = {CascadeType.MERGE, CascadeType.REMOVE, CascadeType.REFRESH, CascadeType.DETACH})
    private Set<Place> places = new HashSet<>();

    public void addPlace(Place placeToPersist) {
        this.places.add(placeToPersist);
    }
}

And there is how I save this. The point is I want to link place with existing in database tags, but if the tag is new, it should save it.

public void processForm(Place placeToPersist, Set<Tag> tagsToCheck) {
    Set<Tag> tmpSet = new HashSet<>();

    for (Tag t : tagsToCheck) {
        Tag tagFromDatabase = tagService.findByName(t.getName());
        if (tagFromDatabase == null) {
            t.addPlace(placeToPersist);
            tagService.save(t); //why I can't save here my tag? 
            tmpSet.add(t);
        } else {
            tagFromDatabase.addPlace(placeToPersist);
            tmpSet.add(tagFromDatabase);
        }
    }
    placeToPersist.setTags(tmpSet);
    placeService.save(placeToPersist);
}

Log

org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: pl.project.app.model.Place
Jakub Pomykała
  • 2,082
  • 3
  • 27
  • 58

2 Answers2

2

why I can't save here my tag?

Just as the error says: because you're trying to save a Tag that has a reference to a Place, although the Place is not persistent yet. And since there is no cascade set for the SAVE (or PERSIST, depending on what the save() method does) operation, the Place isn't saved when saving the tag.

So, save the place first, then add the place to the tag and save the tag (or save the tag and then add the place to the tag).

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
0

try putting @Transactional on the method/class or autowiring a TransactionTemplate to use for executing the query