0

I'm working with three object, let's call them Who, What, Where. Their intersection is unique and requires a fourth entity: WhatWhere. I'm struggling with how to setup the classes and annotations to make this work. Note, the What and the Where are unidirectional; they're just lookup tables.

public class Who {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long whoId;

    @OneToMany(mappedBy = "whoId", fetch = FetchType.EAGER)
    private List<WhatWhere> whatWhere;
}
public class What {
    @Id
    @Nationalized
    @Column(name = "whatId",length = 3)
    private String whatId;
}
public class Where {
    @Id
    private Integer whereId;
}

At this point, I've seen two strategies for the joining entity: either make it a @IdClass

@IdClass(WhatWhere.class)
public class WhatWhere implements Serializable {
    @ManyToOne
    @JoinColumn(insertable = false, updatable = false, name = "whoId")
    private Who who;
    
    @ManyToOne
    @JoinColumn(insertable = false, updatable = false, name = "whatId")
    private What what;
    
    @ManyToOne
    @JoinColumn(insertable = false, updatable = false, name = "whereId")
    private Where where;
}

or create an @EmbeddedId.

public class WhatWhere {
    @Embeddable
    public static class WhatWherePK implements Serializable {
        @Column(nullable = false, updatable = false, name = "whoId")
        private Long whoId;

        @Column(nullable = false, updatable = false, length = 3, name = "whatId")
        private String whatId;

        @Column(nullable = false, updatable = false, name = "whereId")
        private Integer whereId;
    }

    @EmbeddedId
    private WhatWherePK pk;
    
    @ManyToOne
    @JoinColumn(insertable = false, updatable = false)
    private Who who;
    
    @ManyToOne
    @JoinColumn(insertable = false, updatable = false)
    private What what;
    
    @ManyToOne
    @JoinColumn(insertable = false, updatable = false)
    private Where where;
}

Related: what is the expected way to populate and persist these objects? I am attempting this approach

public void doSave(What what, Where where){ // assumes 2 objects with ids
    Who who = new Who();
    whoRepository.save(who); // gets an id from the db

    WhatWhere whatWhere = new WhatWhere();
    whatWhere.setWho(who);
    whatWhere.setWhat(what);
    whatWhere.setWhere(where);
    whatWhereRepository.save(whatWhere); // expect it to composite pk
}

However, if I have the objects mapped with as @IdClass, the JPA Repository give an error about failing to convert one of the objects into its respective @Id field type. OTOH, when it's configured to use an @EmbeddedId, it would appear that I have to populate the PK class as well? That seems like a lot of procedural effort - is Hibernate not able to infer that wiring?

The application is using Spring Boot 2.3.2 and Hibernate 5.4.2

Jens Schauder
  • 77,657
  • 34
  • 181
  • 348
end-user
  • 2,845
  • 6
  • 30
  • 56

0 Answers0