Search code examples
javasqlhibernatejpa

Java, JPA relations incorrect query


I have Entity:

@Entity
@Table(schema = "product", name = "product_terminations")
public class ProductTerminations extends BaseEntity {
    @Id
    @SequenceGenerator(name = "product_terminations_id_seq", sequenceName = "product_terminations_id_seq", schema = "product")
    @GeneratedValue(generator = "product_terminations_id_seq", strategy = GenerationType.SEQUENCE)
    private Long id;

    @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinColumn(name = "product_detail_id", referencedColumnName = "id")
    private ProductDetails productDetails;

    @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinColumn(name = "termination_id", referencedColumnName = "id")
    private Termination termination;

    @Type(type = "pgsql_enum")
    @Enumerated(EnumType.STRING)
    @Column(name = "status", nullable = false)
    private ProductSubObjectStatus productSubObjectStatus;
}

And this entity is related with another entity:

@Table(schema = "product", name = "product_details")
public class ProductDetails extends BaseEntity {
...
@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinTable(
            name = "product_terminations",
            schema = "product",
            inverseJoinColumns = @JoinColumn(name = "product_detail_id", referencedColumnName = "id")
    )
    private List<ProductTerminations> terminations;
...

When i'm trying to save terminations to parent entity like this:

private void createProductTerminationGroupsAndAssignTerminationGroups(ProductDetails productDetails, List<TerminationGroup> terminationGroups) {
        productDetails
                .setTerminationGroups(
                        terminationGroups
                                .stream()
                                .map(terminationGroup ->
                                        new ProductTerminationGroups(null, productDetails, terminationGroup, ProductSubObjectStatus.ACTIVE))
                                .collect(Collectors.toList())
                );

        productDetailsRepository.saveAndFlush(productDetails);
    }

I'm getting Hibernate exception:

ERROR org.hibernate.engine.jdbc.spi.SqlExceptionHelper - ERROR: column "product_details_id" of relation "product_terminations" does not exist

Hibernate SQL query Hibernate:

insert into product.product_terminations (product_details_id, product_detail_id) 
values (?, ?)

Where am I going wrong?

Update: Table creation statements:

create table product_terminations
(
    id                    bigint generated by default as identity
        constraint product_terminations_pk
            primary key,
    product_detail_id     bigint                           not null
        constraint product_terminations_product_fk
            references product_details,
    termination_id        bigint                           not null
        constraint product_terminations_termination_fk
            references terminations,
    status                product.product_subobject_status not null,
    create_date           timestamp with time zone         not null,
    system_user_id        varchar(50)                      not null,
    modify_date           timestamp with time zone,
    modify_system_user_id varchar(50)
)
create table product_details
(
id                                    bigint generated by default as identity (maxvalue 2147483647)
        constraint product_details_pk
            primary key,
...
product_id                            bigint
        constraint product_details_product_fk
            references products,
...
)

Solution

  • By adding the @JoinTable annotation, you've made the OneToMany into a unidirectional mapping, telling JPA that there is a "product_terminations" join table that references the ProductTerminations entity, and that it has a "product_detail_id" column that references the ProductTerminations' ID column.

    What you may have meant to do instead was create a bidirectional relationship, where the "product_detail_id" in ProductTerminations is a foreign key referencing the "product_details" ID instead - which is what you already have in the ProductTerminations.productDetails OneToOne mapping. All that is needed is to remove the JoinTable and connect the OneToMany to use the existing OneToOne mapping:

    @Table(schema = "product", name = "product_details")
    public class ProductDetails extends BaseEntity {
    ...
        @OneToMany(mappedBy= "productDetails", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
        private List<ProductTerminations> terminations;
        ..
    

    Also note, you may want to change the ProductTerminations.productDetails mapping from OneToOne to ManyToOne. Some JPA providers might enforce uniqueness on the fk if it isn't marked as a ManyToOne.