0

I have the following object that I would like to save using hibernate:

@Entity
@Table(name = "setting")
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class Setting
{
    @Id
    @Column(name = "id")
    public String internalID;
    @Column(name = "name")
    public String name;
    @Column(name = "type")
    public String type;
    @Column(name = "regex")
    public String regex;

    @OneToMany(fetch = FetchType.EAGER, cascade = {CascadeType.PERSIST, CascadeType.MERGE})
    @JoinTable(name = "setting",
           joinColumns = {@JoinColumn(name = "parent_id")},
           inverseJoinColumns = {@JoinColumn(name = "id")})
    public Collection<Setting> children;

    @JsonIgnore
    @Column(name = "parent_id")
    public String parentID;

    @Column(name = "value")
    public String value;

    public Setting()
    {
        this.internalID = UUID.randomUUID().toString();
    }
}

Hibernate tries to save this, but it seems to fail with the child objects. When creating a Setting object that is 3 layers deep, only the first 2 layers are saved and the third one is ignored.

Beside that the second layer is only saving the internalID and parentID, leaving name, type and regex null in the database.

save function for the database:

public static void saveObject(Object obj)
{
    if(sessionFactory == null)
        init();
    try(Session session = sessionFactory.openSession())
    {
        session.beginTransaction();
        session.save(obj);
        session.getTransaction().commit();
    }
    catch(Exception e)
    {
        e.printStackTrace();
    }
}

What is it that I am missing? Are the annotations wrong?

Steps to reproduce:

public static void test()
{
    Setting outer = new Setting();
    outer.name = "Outer";
    Setting inner = new Setting();
    inner.name = "Inner";
    outer.children = new ArrayList<>();
    outer.children.add(inner);
    saveObject(outer);
}

public static void saveObject(Object obj)
{
    if(sessionFactory == null)
        initDB();
    try(Session session = sessionFactory.openSession())
    {
        session.beginTransaction();
        session.save(obj);
        session.getTransaction().commit();
    }
    catch(Exception e)
    {
        e.printStackTrace();
    }
}

private static SessionFactory sessionFactory;

private static void initDB()
{
    final StandardServiceRegistry registry = new StandardServiceRegistryBuilder().configure() // configures settings from hibernate.cfg.xml
            .build();
    sessionFactory = new MetadataSources(registry).buildMetadata().buildSessionFactory();
    Runtime.getRuntime().addShutdownHook(new Thread(() ->
    {
        StandardServiceRegistryBuilder.destroy(registry);
    }));
}

with the SQL:

CREATE SCHEMA `cosmos` ;

CREATE TABLE `cosmos`.`setting` (
  `id` VARCHAR(64) NOT NULL,
  `name` VARCHAR(256) NULL,
  `type` VARCHAR(7) NOT NULL,
  `regex` VARCHAR(512) NULL,
  `value` VARCHAR(512) NULL,
  `parent_id` VARCHAR(64) NULL,
  PRIMARY KEY (`id`));

CREATE TABLE `cosmos`.`setting_relation` (
  `id` VARCHAR(64) NOT NULL,
  `parent_id` VARCHAR(64) NULL,
  PRIMARY KEY (`id`));

and the config:

<hibernate-configuration>
    <session-factory name="localConnection">
        <property name="hibernate.dialect">
            org.hibernate.dialect.MySQLDialect
        </property>
        <property name="hibernate.connection.driver_class">
            com.mysql.jdbc.Driver
        </property>

        <property
                name="hibernate.connection.url">
            jdbc:mysql://localhost:3306/cosmos?useSSL=false
        </property>
        <property name="hibernate.connection.username">
            root
        </property>
        <property name="hibernate.connection.password">
            ****
        </property>

        <!-- List of XML mapping files -->
        <mapping class="se.mulander.cosmos.settings.model.Setting"/>
    </session-factory>
</hibernate-configuration>

1 Answer 1

1

try @JoinTable(name = "setting_some_name" instead of @JoinTable(name = "setting"

@OneToMany(fetch = FetchType.EAGER, cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@JoinTable(name = "setting_some_name",
        joinColumns = {@JoinColumn(name = "parent_id")},
        inverseJoinColumns = {@JoinColumn(name = "id")})
public Collection<Setting> children;

or if you want to do it with self join on same table , do this :

@ManyToOne(optional = true)
@JoinColumn(name = "parent_id")
public Setting parent;

@OneToMany(fetch = FetchType.EAGER, mappedBy = "parent" , cascade = {CascadeType.ALL})
public Collection<Setting> children;
Sign up to request clarification or add additional context in comments.

4 Comments

i.imgur.com/PyadZkm.png Hibernate: insert into setting (name, parent_id, regex, type, value, id) values (?, ?, ?, ?, ?, ?) It only atempts one save...
I updated mapping for variant 2. try it , with show_sql ..... @ManyToOne(optional = true) @JoinColumn(name = "parent_id") public Setting parent; @OneToMany(fetch = FetchType.EAGER, mappedBy = "parent" , cascade = {CascadeType.ALL}) public Collection<Setting> children;
Pls remove all coments as it looks as spam.and try this mapping and give your result. And sql log
I went to bed which is why it took some time, but I just tested it and now it works! I cannot thank you enough for the help :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.