Search code examples
javahibernatejpajpa-2.0hibernate-cascade

Cascade within @EmbeddedId in hibernate


I'm adding an intersection table with additional data and I use @EmbeddedId to make a complex ID for the entities which are bound by the record in this table(entity1 and entity2).

I want to save all the data via cascade when I save entity 1. So, that is why in entity 1 I have:

@OneToMany(cascade = {CascadeType.DETACH, CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH},
            fetch = FetchType.LAZY, mappedBy = "id.entity1")
private List<Entity1ToEntity2Link> links = new ArrayList<>();

In Entity1ToEntity2Link I have @EmbeddedId and within it I have links to both entities. But, I want the second one to be saved when I save entity 1. So, I made it like this:

@ManyToOne(cascade = {CascadeType.DETACH, CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH})
private Entity2 entity2;

But, unfortunatelly, the cascade that I have inside @EmbeddedId seems to be ignored. I can see that sql for insert is not generated and when Entity1ToEntity2Link is saved I get an error:

violated - parent key not found

I suspect that @EmbeddedId doesn't support cascades. But, I'm not sure. Do you have any ideas how I can save entity2 before Entity1ToEntity2Link is saved?


Id object:

@Embeddable
public class LinkId extends AbstractLinkId {
    //...
    @ManyToOne(cascade = {CascadeType.DETACH, CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH})
    private Entity2 entity2;
    //...
}


@MappedSuperclass
public class AbstractLinkId {
    //...
    @ManyToOne
    private Entity1 entity1;
    //...
}

Solution

  • Instead of using the Entity1ToEntity2Link try a direct ManyToMany relation.

    public class Entity1 {
    
        @ManyToMany
        @JoinTable(
            name="LINK_TABLE_NAME",
            joinColumns=@JoinColumn(name="ENTITY1_ID", referencedColumnName="ID"),
            inverseJoinColumns=@JoinColumn(name="ENTITY2_ID", referencedColumnName="ID"))
        private List<Entity2> entities2;
    }
    
    public class Entity2 {
    
        @ManyToMany(mappedBy="entities2")
        private List<Entity1> entities1;
    }
    

    The problem with your the approach is the following. You try to call save on Entity1 which cascades it down to the Entity1ToEntity2Link. Now Entity1ToEntity2Link needs Entity1 for the primary key but Entity1 does not exist yet.

    Their are two ways to get it saved by using Entity1ToEntity2Link .

    First: Don't add cascade to Entity1ToEntity2Link and save the links after saving Entity1.

    Second: Add a generated Id to the Entity1ToEntity2Link.