2

I want to implement a one-to-many relation using Hibernate (in Java). I have two entities:

  • Experiment
  • ExperimentGroup

Experiment has many ExperimentGroups. I tried to configure this one-to-many relation, the way the official Hibernate document recommends: http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/example-parentchild.html#example-parentchild-cascades

My config file:

<class name="ExperimentImpl" table="Experiment">
    <id name="id" type="int" column="id">
        <generator class="increment" />
    </id>
    <!-- One to Many   -->
    <set name="experimentGroups" table="ExperimentGroup" 
                lazy="false" fetch="select" cascade="all" inverse="true">
            <key>
                <column name="Experiment_id" not-null="true" />
            </key>
            <one-to-many class="ExperimentGroupImpl" />
    </set>  
</class>
<class name="ExperimentGroupImpl" table="ExperimentGroup">
    <id name="id" type="int" column="id">
        <generator class="increment" />
    </id>
    <many-to-one name="experiment" class="ExperimentImpl" fetch="select">
            <column name="Experiment_id" not-null="true" />
    </many-to-one>
</class>

Adding a new ExperimentGroup to an Experiment works fine, but deleting an Experiment (and all of its ExperimentGroups) causes an exception:

Cannot delete or update a parent row: a foreign key constraint fails (testdb.ExperimentGroup, CONSTRAINT FK9C71D86238B5500C FOREIGN KEY (Experiment_id) REFERENCES Experiment (id))

My ExperimentDAO code looks like this:

public void deleteExperiment(Experiment experiment) 
         throws DAOException
    {
        Session session = null;
        Transaction t = null;
        try{
            session = HibernateUtil.getSessionFactory().openSession();
            t = session.beginTransaction();
                session.delete(experiment);
            t.commit();
            session.flush();
            session.close();
        }catch (HibernateException e)
        {
            e.printStackTrace();
            if (t != null)
                t.rollback();

            if (session != null)
                session.close();

            throw new DAOException(e, "Could not delete Experiment");
        }
    }

EDIT: The DAO code to create an Experiment and ExperimentGroup:

public Experiment createExperiment(String name, String description, RegisteredUser owner)
{
    Transaction tx = null;
    Session session = null;
    try
    {
        session = HibernateUtil.getSessionFactory().openSession();

        tx= session.beginTransaction();
        ExperimentImpl e = new ExperimentImpl();

        e.setName(name);
        e.setDescription(description);
        e.setOwner(owner);

        owner.getOwnedExperiments().add(e);

        session.save(e);
        tx.commit();
        session.flush();
        session.close();

        return e;
    } catch (HibernateException ex )
    {
        if (tx != null)
            tx.rollback();

        if (session!=null)
            session.close();

        throw ex;
    }
}




public ExperimentGroup createAndAddExperimentGroup(Experiment experiment, String experimentGroupName, Date startDate, Date endDate) throws ArgumentException
    {

        Transaction t = null;
        Session session = null;

        try
        {
            session = HibernateUtil.getSessionFactory().openSession();
            t = session.beginTransaction();
                ExperimentGroupImpl g = new ExperimentGroupImpl();
                g.setEndDate(endDate);
                g.setStartDate(startDate);
                g.setName(experimentGroupName);
                g.setExperiment(experiment);

                experiment.getExperimentGroups().add(g);
                g.setExperiment(experiment);

                session.save(g);
                session.update(experiment);
            t.commit();
            session.flush();
            session.close();

            return g;

        }catch(HibernateException e)
        {
            if (t!=null)
                t.rollback();

            if (session!= null)
                session.close();

            throw e;
        }
    }

There are many other properties for an Experiment, like the name, description etc., which I have removed from the config file, because they don't have an impact on the one-to-many relation.

Any suggestion? What did I wrong?

nikiforovpizza
  • 487
  • 1
  • 7
  • 13
sockeqwe
  • 15,574
  • 24
  • 88
  • 144
  • The error suggests that Hibernate is trying to delete the parent Experimient entity without deleting all the ExperimentGroups first. Can you post the code in which you build your Experiment / ExperimentGroup entities? – Gonzalo Garcia Lasurtegui Nov 26 '11 at 22:14
  • Hi, thank you for your answer. I put the code in the "question" (above). – sockeqwe Nov 26 '11 at 23:56
  • @sockeqwe: Have you got `ON DELETE CASCADE` clause for your foreign key constraint? If not, then the situation is clear: when you try to delete the parent entity and Hibernate follows one-to-many association, then Hibernate first deletes the child entities and then the parent. If Hibernate does not know about this association, then deletion the parent entity does not cause the deletion of children and this causes the constraint violation. It's not clear for me, why you provided the code sample for `RegisteredUser` entity... – dma_k Nov 27 '11 at 10:50
  • Hi, thank you for your Help, but the ON DELETE CASCADE is not needed, because Hibernate should take care of this problem. The problem is solved (see the next answere) – sockeqwe Nov 27 '11 at 11:06

1 Answers1

1

I am under the impression that you are trying to delete a detached entity that you manually created. I would try to use the primary key of the Experiment you want to delete, and load before actually deleting it:

session = HibernateUtil.getSessionFactory().openSession();
t = session.beginTransaction();
ExperimentImpl persistentExperiment = session.load(ExperimentImpl.class, experiment.getId());
session.delete(persistentExperiment);
t.commit();
  • Oh, thank that solved the problem ... I thought hibernate take care of attaching a entity to new session ... Whats the normal way to stay in sync with my Experiment object in the the application layer? Hibernate.merge()? – sockeqwe Nov 27 '11 at 11:07