Home > Software engineering >  Hibernate generate wrong sql query for inserting child entity
Hibernate generate wrong sql query for inserting child entity

Time:10-16

i have a one to many entity association model in this way:


@Entity
@Table(name = "father")
public class Father {

    @Id
    @GeneratedValue
    @Column(columnDefinition = "BINARY(16)", updatable = false)
    @Type(type="org.hibernate.type.UUIDBinaryType")
    private UUID id;

    ...

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "father", orphanRemoval = true)
    private List<AbstractChild> children = new ArrayList<>();

    ...
    

}




@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(
        name="type",
        discriminatorType = DiscriminatorType.INTEGER,
        columnDefinition = "TINYINT(1) NOT NULL")
@Table(
    name = "child",
    uniqueConstraints = @UniqueConstraint(columnNames = {"type", "name", "father_id"})
)
@IdClass(Child.class)
public abstract class AbstractChild implements Serializable {

    @Id
    @Column(nullable = false)
    protected Locale locale;

    @Id
    @ManyToOne(fetch = FetchType.LAZY)
    protected Father father;

    @Id
    @Column(name = "type", insertable = false, updatable = false)
    protected short mediaType;

    ...

}



@Entity
@DiscriminatorValue("1")
public class ConcreteChildOne extends AbstractChild {

    @Lob
    private String content;

    ...

}



@Entity
@DiscriminatorValue("2")
public class ConcreteChildTwo extends AbstractChild {

    @Column(name = "path")
    private String path;

    ...

}

Everything seems fine but when i save a Father entity with children, the values order in generated sql is wrong.

The insert query for the father is ok

insert 
    into
        father
        (description, name, id) 
    values
        (?, ?, ?)

has those binding parameters

  • binding parameter [1] as [VARCHAR] - [description]
  • binding parameter [2] as [VARCHAR] - [name]
  • binding parameter [3] as [BINARY] - [3bfac6e0-08ec-4f6b-a62a-5626ee6ab0e5]

But the insert query for the child is wrong

    insert 
    into
        tourist_informations
        (content, type, father_id, locale) 
    values
        (?, ?, ?, ?)
  • binding parameter [1] as [CLOB] - [this is my content]
  • binding parameter [2] as [BINARY] - [3bfac6e0-08ec-4f6b-a62a-5626ee6ab0e5]
  • binding parameter [3] as [SMALLINT] - [1]
  • binding parameter [4] as [VARCHAR] - [en_EN]

The sql to create database is

    create table father (
        id BINARY(16) not null,
        description varchar(255),
        name varchar(150) not null,
        primary key (id)
    ) engine=InnoDB
    
    create table child (
        type TINYINT(1) NOT NULL ,
        locale varchar(255) not null,
        path varchar(255),
        content longtext,
        father_id BINARY(16) not null,
        primary key (father_id, type, locale)
    ) engine=InnoDB
    
    alter table tourist_informations 
       add constraint FKpem984v0clq1bsvubkkynoq7x 
       foreign key (father_id) 
       references father (id)

Someone as an idea why the order is wrong? Thank you in advice.

CodePudding user response:

I think your mapping is wrong. It should be:

@OneToMany(cascade = CascadeType.ALL, mappedBy = "father", orphanRemoval = true)
private List<AbstractChild> children = new ArrayList<>();

CodePudding user response:

I have found a map that works:


@Entity
@Table(name = "father")
public class Father {

    @Id
    @GeneratedValue
    @Column(columnDefinition = "BINARY(16)", updatable = false)
    @Type(type="org.hibernate.type.UUIDBinaryType")
    private UUID id;

    ...

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "father", orphanRemoval = true)
    private List<AbstractChild> children = new ArrayList<>();

    ...
    

}


@Embeddable
public class ChildID implements Serializable {

    @Column(name = "type")
    protected short type;

    @Column(nullable = false)
    protected String name;

    @Column(columnDefinition = "BINARY(16)", name = "father_id")
    @Type(type="org.hibernate.type.UUIDBinaryType")
    private UUID fatherId;

    ...

}



@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(
        name="type",
        discriminatorType = DiscriminatorType.INTEGER,
        columnDefinition = "TINYINT(1) NOT NULL")
@DiscriminatorOptions(force = true, insert = false)
@Table(
    name = "child",
    uniqueConstraints = @UniqueConstraint(columnNames = {"type", "name", "father_id"})
)
@IdClass(Child.class)
public abstract class AbstractChild implements Serializable {

    @EmbeddedId
    private ChildID id;

    public AbstractChild() {
        this.id = new ChildID();
    }

    @ManyToOne(fetch = FetchType.LAZY)
    @MapsId("fatherId")
    protected Father father;

    ...

}



@Entity
@DiscriminatorValue("1")
public class ConcreteChildOne extends AbstractChild {

    @Lob
    private String content;

    public ConcreteChildOne() {
        super();
        this.getId().type = 1;
    }

    ...

}



@Entity
@DiscriminatorValue("2")
public class ConcreteChildTwo extends AbstractChild {

    @Column(name = "path")
    private String path;

    public ConcreteChildTwo() {
        super();
        this.getId().type = 2;
    }

    ...

}

Of course you can improve the code using delegate method to set type on embedde d id or pass it with super() into constructor but those things are details.

Hope that answer can help Thank you all for your answer

  • Related