Shared column between FK and PK

69 Views Asked by At

I have two tables, A and B (not defined by me, inherited from old legacy software), with the following structure:

A: PK (idA, ente),

B: PK(idB, ente), FK(idA, ente) --> A

I need to use @IdClass/@Id, rather than @Embeddeble/@EmbeddebleId, because @GeneratedValue on id columns.

I'd like to insert a new couple of rows this way:

A a = new A();
a.setEnte('E1');
a = repA.save(a);

B b = new B();
b.setA(a);
b = repB.save(b);

I use Spring Data JPA's repositories class. My best try, was:

@Getter
@ToString
@Setter
@Entity
@Table(name = "address")
@IdClass(BPK.class)
@NoArgsConstructor
public class B  implements Serializable{
    
    @ManyToOne
    @JoinColumns({
        @JoinColumn(name="idA", referencedColumnName="idA", nullable=false, insertable=false, updatable=false),
        @JoinColumn(name="ente", referencedColumnName="ente", nullable=false, insertable=false, updatable=false)
        })
    private A a;

    @Id
    @org.hibernate.annotations.GenericGenerator(name = "incrementGenerator", strategy = "org.hibernate.id.IncrementGenerator")
    @GeneratedValue(generator="incrementGenerator")
    @Column(name = "idB", columnDefinition = "int(10)", nullable = false)
    private Integer idB;

    @Id
    @Column(insertable=false, updatable=false, unique=true, nullable=false, length=6)
    private String ente;
}


@Getter
@ToString
@Setter
@Entity
@Table(name = "Users")
@IdClass(APK.class)
@NoArgsConstructor
public class A implements Serializable {

    @Id
    @org.hibernate.annotations.GenericGenerator(name = "incrementGenerator", strategy = "org.hibernate.id.IncrementGenerator")
    @GeneratedValue(generator="incrementGenerator")
    @Column(name = "idA", columnDefinition = "int(10)", nullable = false)
    private Integer idA;

    @Id
    @Column(name = "ente", columnDefinition = "char(6)", nullable = false)
    public String ente;
}

This solution doesn't work, because idA and ente are not inserted in save(b) instruction. If I change insertable=true in the @ManyToOne lines, there will be error on ente field.

Any suggestions?

1

There are 1 best solutions below

0
Tiziano Ruaro On BEST ANSWER

Your b.setA() method could also set this automatically

Thanks to Christian Beikov's suggestion, I found an acceptable solution to the problem. Why it should not infer data directly from the entities is not clear to me.

However, the solution is to force the missing data to be set before persisting using @PrePersist.

The model for B becomes:

@Getter
@ToString
@Setter
@Entity
@Table(name = "address")
@IdClass(BPK.class)
@NoArgsConstructor
public class B  implements Serializable{
    
        @ManyToOne
    @JoinColumns({
        @JoinColumn(name="idA", referencedColumnName="idA", nullable=false, insertable=false, updatable=false),
        @JoinColumn(name="ente", referencedColumnName="ente", nullable=false, insertable=false, updatable=false)
        })
    private A a;

    @Id
    @org.hibernate.annotations.GenericGenerator(name = "incrementGenerator", strategy = "org.hibernate.id.IncrementGenerator")
    @GeneratedValue(generator="incrementGenerator")
    @Column(name = "idB", columnDefinition = "int(10)", nullable = false)
    private Integer idB;

    @Id
    @Column(insertable=false, updatable=false, unique=true, nullable=false, length=6)
    private String ente;
    
//New lines (In the real code I used getters, of course) <--
    @Column(name = "idA", nullable = false, columnDefinition = "int(10)")
    private Integer idA;

    @PrePersist
    private void init() {
        this.ente = a.ente;
        this.idA= a.idA;
    }
}