How to do bulk inserts when you have a @UniqueConstraint in a related entity?

Viewed 39

So I have a many-to-many relationship that goes like this:

@Entity
@Table(name="A")
public class A {
    @Id
    @SequenceGenerator(...)
    @GeneratedValue(strategy = SEQUENCE, ...)
    private Long id;

    @ManyToMany(
        cascade = CascadeType.PERSIST,
        fetch = FetchType.EAGER
    )
    @JoinTable(...)
    private Set<B> b;

}

I have cascade = CascadeType.PERSIST in the many-to-many relationship so that when I save A, B is persisted along with it. But, as you can see B has a @UniqueConstraint:

@Entity
@Table(
    name="B",
    uniqueConstraints = @UniqueConstraint(name = "b_name_unique", columnNames = "name")
)
public class B {
    @Id
    @SequenceGenerator(name = "b_sequence", sequenceName = "b_sequence", allocationSize = 1)
    @GeneratedValue(strategy = SEQUENCE, generator = "b_sequence")
    private Long id;

    @Column(name = "name", nullable = false)
    private String name;

    @ManyToMany(mappedBy = "b")
    private Set<A> a;

}

The problem is, of course, when try to save two different A entities with B entities with the same name, or even with the exact same B entity, it throws the following error:

Caused by: org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "b_name_unique"
  Detail: Key (name)=(myname) already exists.

Which makes sense, since it's doing the following:

Hibernate: insert into B (name, id) values (?, ?)

o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [VARCHAR] - [myname] <--------------------\
o.h.type.descriptor.sql.BasicBinder      : binding parameter [2] as [BIGINT] - [1]                            |
                                                                                                              |
Hibernate: insert into B (name, id) values (?, ?)                                                             |
                                                                                                              |
o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [VARCHAR] - [myname] <--------------------|
o.h.type.descriptor.sql.BasicBinder      : binding parameter [2] as [BIGINT] - [2] <--------- +1 even though name is the same
o.h.engine.jdbc.spi.SqlExceptionHelper   : SQL Error: 0, SQLState: 23505                                                   |
o.h.engine.jdbc.spi.SqlExceptionHelper   : ERROR: duplicate key value violates unique constraint "b_name_unique" <---------/

What I want to do is find a way to save multiple A entities that have B entities in common. For example:

save A(id=null, b=B(id=null, name=myname)) -> find A(id=1, b=B(id=1, name=myname))
save A(id=null, b=B(id=null, name=myname)) -> find A(id=2, b=B(id=1, name=myname))

The only workaround I've found so far is to:

  • make a set of all the common B entities in A entities and
  • save those first, and then
  • save the A entities.

And that works somehow.

0 Answers
Related