0

I'm a bit confused about the way Hibernate handles inserts into the JoinTable.

I need some extra fields in the JoinTable, so I chose the pretty common way, to create an @Entity for the JoinTable and use @OneToMany and @ManyToOne. And because the relations should be unique I created an @EmbeddedId within the JoinTable-Entity.

Lets call the classes A, B and AB:

@Entity
public class A implements Serializable {
    @OneToMany(mappedBy="a", cascade=CascadeType.ALL, orphanRemoval=true)
    private Set<AB> abs;        
}

@Entity
public class B implements Serializable {
    @OneToMany(mappedBy="b", cascade=CascadeType.ALL, orphanRemoval=true)
    private Set<AB> abs;        
}

@Entity
public class AB implements Serializable {
    @Embeddable
    public static class Id implements Serializable {
        UUID aId;
        UUID bId;

        public Id(UUID aId, UUID bId) {
            this.aId = aId;
            this.bId = bId;
        }
    }

    public AB(A a, B b) {
        this.id.aId = a.getId();
        this.id.bId = b.getId();
        this.a = a;
        this.b = b;
    }

    @EmbeddedId
    private Id id;      

    @MapsId("aId")
    @ManyToOne
    @JoinColumn(nullable=false, updatable=false)
    private A a;

    @MapsId("bId")
    @ManyToOne
    @JoinColumn(nullable=false, updatable=false)
    private B b;        
}

My commons case is, that I want to insert multiple new entries in to the JoinTable. So I have ONE A_id and multiple B_ids. In plain SQL, I'd simply do ONE query to get it all done. If the relation did already exist, the database will throw an error.

With hibernate I need to:

  1. SELECT: give me an instance of class A for id = A_id
  2. SELECT: give me an instance of class B for id = B_id1 or id = B_id2 or ...
  3. Create a new instance of class AB and set the composite primary key and save AB

The last step produces (for each AB):

  1. select * from AB where a_id = ... and b_id = ...
  2. insert into AB (aId, bId) values (..., ...)

Here's my code. Using spring data jpa (JpaRepository):

A a = aRepo.findOne(aId);
List<B> bs = bRepo.findAll(bIdList);
for(B b : bs) {
    AB ab = new AB(a, b);
    abRepo.save(ab);
}
groupUserRepo.flush();

It doesn't matter if I just create a new ArrayList with the AB objects and afterwards save all of them at once or if I do it like in the code above. It always does a select and an insert for each object.

Is there a way to do it with less queries?

Benjamin M
  • 23,599
  • 32
  • 121
  • 201

1 Answers1

0

This is wierd as what you are seeing is the behavior of saveOrUpdate for a detached object. I would expect hibernate to issue select for A and for B if they were detached object but not for AB as you are calling save.

Can you try with persist to see if it changes anything.

Manuel Darveau
  • 4,585
  • 5
  • 26
  • 36
  • Thank you for the answer. The problem is: I'm using spring-data-jpa, which doesn't provide methods like persist or merge. It has only `save` and `saveAndFlush`. – Benjamin M Sep 27 '13 at 02:42
  • Try implementing Persistable. See http://docs.spring.io/spring-data/jpa/docs/1.4.1.RELEASE/reference/html/jpa.repositories.html#jpa.entity-persistence.saving-entites – Manuel Darveau Sep 28 '13 at 18:42