Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

foreign key no parent error

Tags:

java

hibernate

This is really why I quit using Hibernate to manage my relationships for me. Too many new gray hairs.

Hibernate 3.6.10

OK, I have two classes, Schedule and Event. Schedule has many events, but an event has only one schedule.

Schedule:

/**
 * 
 */
package com.heavyweightsoftware.leal.model.schedule;

import java.util.ArrayList;
import java.util.Collection;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.Table;

import com.heavyweightsoftware.leal.helper.DateHelper;
import com.heavyweightsoftware.leal.model.Pojo;

/**
 * A particular collection of events that can be shared
 * @author Thom
 */
@Entity
@Table(name = "SCHEDULE")
@NamedQueries( {
    @NamedQuery(name = Schedule.COUNT_SCHED_ID,      query =  "SELECT COUNT(*) " +
                                                              "FROM Schedule s " +
                                                              "WHERE s.scheduleId = :scheduleId"),
    @NamedQuery(name = Schedule.COUNT_SCHED_NAME,    query =  "SELECT COUNT(*) " +
                                                              "FROM   ScheduleRole r, Schedule s, SystemUser u " +
                                                              "WHERE  u.email = :email " +
                                                               " AND u.id = r.systemUserId " +
                                                               " AND r.scheduleId = s.id " +
                                                               " AND s.name = :scheduleName "),
    @NamedQuery(name = Schedule.QUERY_EVENTS_BY_USER, query =  "SELECT  r.roleType, s " +
                                                               "FROM    Schedule s, ScheduleRole r, SystemUser u " +
                                                               "WHERE   u.email = :email " +
                                                               "  AND   u.id = r.systemUserId " +
                                                               "  AND   r.scheduleId = s.id " +
                                                               " ")
    }
)
public class Schedule extends Pojo {

    public static final int        LENGTH_SCHEDULE_ID        = 32;
    public static final String     COUNT_SCHED_ID            = "countScheduleId";
    public static final String     COUNT_SCHED_NAME          = "countScheduleName";
    public static final String     QUERY_EVENTS_BY_USER      = "findEventsByUser";

    @Column(name = "ID", nullable=false)
    @Id @GeneratedValue(strategy=GenerationType.AUTO)
    private Integer     id;

    @Column(name = "NAME", nullable=false)
    private String      name;

    @Column(name = "SCHEDULE_ID", nullable=false, unique=true, length=LENGTH_SCHEDULE_ID)
    private String      scheduleId;

    @OneToMany(cascade = CascadeType.ALL, fetch=FetchType.EAGER, orphanRemoval=true)
    @JoinColumn(name="ID")
    private Collection<Event>   events;

    /**
     * Copy all members from one to the other
     * @param from the from
     * @param to the to
     * @param copySubMembers if true, copy sub members like entity
     */
    public static void copy(Schedule from, Schedule to, boolean copySubMembers){
        to.setId(from.getId());
        to.setName(from.getName());
        to.setScheduleId(from.getScheduleId());
        if(copySubMembers){
            to.setEvents(from.getEvents());
        }
    }

    /**
     * no-arg constructor
     */
    public Schedule() {
    }

    /**
     * copy constructor
     */
    public Schedule(Schedule schedule) {
        copy(schedule, this, true);
    }

    /* (non-Javadoc)
     * @see com.heavyweightsoftware.leal.model.Pojo#toString()
     */
    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder(super.toString());
        sb.append('|');
        sb.append(getName());
        sb.append('|');
        sb.append(getScheduleId());
        sb.append('|');
        sb.append(getEvents());
        return sb.toString();
    }

    /* (non-Javadoc)
     * @see java.lang.Object#hashCode()
     */
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = super.hashCode();
        result = prime * result + ((id == null) ? 0 : id.hashCode());
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        result = prime * result
                + ((scheduleId == null) ? 0 : scheduleId.hashCode());
        return result;
    }

    /* (non-Javadoc)
     * @see java.lang.Object#equals(java.lang.Object)
     */
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (!super.equals(obj))
            return false;
        if (getClass() != obj.getClass())
            return false;
        Schedule other = (Schedule) obj;
        if (id == null) {
            if (other.id != null)
                return false;
        } else if (!id.equals(other.id))
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        if (scheduleId == null) {
            if (other.scheduleId != null)
                return false;
        } else if (!scheduleId.equals(other.scheduleId))
            return false;
        return true;
    }

    /**
     * @return the id
     */
    public final Integer getId() {
        return id;
    }

    /**
     * @param id the id to set
     */
    public final void setId(Integer id) {
        this.id = id;
    }

    /**
     * @return the name
     */
    public final String getName() {
        return name;
    }

    /**
     * @param name the name to set
     */
    public final void setName(String name) {
        this.name = name;
    }

    /**
     * @return
     */
    public String getScheduleId() {
        return scheduleId == null?scheduleId = DateHelper.getUniqueID():scheduleId;
    }

    /**
     * @param scheduleId
     */
    public void setScheduleId(String scheduleId) {
        this.scheduleId = scheduleId;
    }

    /**
     * @return the events
     */
    public Collection<Event> getEvents() {
        return events==null?events = new ArrayList<>():events;
    }

    /**
     * @param events the events to set
     */
    public void setEvents(Collection<Event> events) {
        this.events = events;
    }
}

Event:

/**
 * 
 */
package com.heavyweightsoftware.leal.model.schedule;

import java.util.Calendar;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

import com.heavyweightsoftware.leal.model.Pojo;

/**
 * A particular event entry in a calendar
 * @author Thom
 */
@Entity
@Table(name = "EVENT")
@NamedQueries( {
    }
)
public class Event extends Pojo {

    /**
     * Length of the randomly generated event ID
     */
    private static final int            LENGTH_EVENT_ID             = 32;

    @Column(name = "ID", nullable=false)
    @Id @GeneratedValue(strategy=GenerationType.AUTO)
    private Integer     id;

    @Column(name = "START_TIME")
    @Temporal(TemporalType.TIMESTAMP)
    private Calendar    start;

    @Column(name = "END_TIME")
    @Temporal(TemporalType.TIMESTAMP)
    private Calendar    end;

    @Column(name = "EVENT_NAME", nullable=false)
    private String      eventName;

    @Column(name = "EVENT_ID", nullable=false, unique=true, length=LENGTH_EVENT_ID)
    private String      eventId;

    @ManyToOne(fetch=FetchType.EAGER)
    @JoinColumn(name="SCHEDULE_ID")
    private Schedule    schedule;

    @Column(name = "LOCATION")
    private String      location;

    /* (non-Javadoc)
     * @see java.lang.Object#hashCode()
     */
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = super.hashCode();
        result = prime * result + ((end == null) ? 0 : end.hashCode());
        result = prime * result
                + ((eventName == null) ? 0 : eventName.hashCode());
        result = prime * result + ((id == null) ? 0 : id.hashCode());
        result = prime * result
                + ((location == null) ? 0 : location.hashCode());
        result = prime * result
                + ((schedule == null) ? 0 : schedule.hashCode());
        result = prime * result + ((start == null) ? 0 : start.hashCode());
        return result;
    }

    /* (non-Javadoc)
     * @see java.lang.Object#equals(java.lang.Object)
     */
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (!super.equals(obj))
            return false;
        if (getClass() != obj.getClass())
            return false;
        Event other = (Event) obj;
        if (end == null) {
            if (other.end != null)
                return false;
        } else if (!end.equals(other.end))
            return false;
        if (eventName == null) {
            if (other.eventName != null)
                return false;
        } else if (!eventName.equals(other.eventName))
            return false;
        if (id == null) {
            if (other.id != null)
                return false;
        } else if (!id.equals(other.id))
            return false;
        if (location == null) {
            if (other.location != null)
                return false;
        } else if (!location.equals(other.location))
            return false;
        if (schedule == null) {
            if (other.schedule != null)
                return false;
        } else if (!schedule.equals(other.schedule))
            return false;
        if (start == null) {
            if (other.start != null)
                return false;
        } else if (!start.equals(other.start))
            return false;
        return true;
    }

    /* (non-Javadoc)
     * @see com.heavyweightsoftware.leal.model.Pojo#toString()
     */
    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append(super.toString());
        sb.append('|');
        sb.append(getEventName());
        sb.append('|');
        sb.append(getTimestamp(getStart()));
        sb.append('-');
        sb.append(getTimestamp(getEnd()));
        sb.append("|scheduleId=");
        Schedule schedule = getSchedule();
        sb.append(schedule==null?"null":schedule.getId());
        sb.append('|');
        sb.append(getLocation());
        sb.append('|');
        sb.append(getEventId());
        return sb.toString();
    }

    /**
     * @return the id
     */
    public final Integer getId() {
        return id;
    }

    /**
     * @param id the id to set
     */
    public final void setId(Integer id) {
        this.id = id;
    }

    /**
     * The start date of the event in UTC
     * @return the start
     */
    public final Calendar getStart() {
        return start;
    }

    /**
     * The start date of the event in UTC
     * @param start the start to set
     */
    public final void setStart(Calendar start) {
        this.start = start;
    }

    /**
     * The end date of the event in UTC
     * @return the end
     */
    public final Calendar getEnd() {
        return end;
    }

    /**
     * The end date of the event in UTC
     * @param end the end to set
     */
    public final void setEnd(Calendar end) {
        this.end = end;
    }

    /**
     * @return the eventId
     */
    public String getEventId() {
        return eventId;
    }

    /**
     * @param eventId the eventId to set
     */
    public void setEventId(String eventId) {
        this.eventId = eventId;
    }

    /**
     * @return the eventName
     */
    public final String getEventName() {
        return eventName;
    }

    /**
     * @param eventName the eventName to set
     */
    public final void setEventName(String eventName) {
        this.eventName = eventName;
    }

    /**
     * @return the location
     */
    public final String getLocation() {
        return location;
    }

    /**
     * @param location the location to set
     */
    public final void setLocation(String location) {
        this.location = location;
    }

    /**
     * @return the schedule
     */
    public Schedule getSchedule() {
        return schedule;
    }

    /**
     * @param schedule the schedule to set
     */
    public void setSchedule(Schedule schedule) {
        this.schedule = schedule;
    }
}

Now at the point I'm getting the exception, I have created a schedule and then added 4 events to the schedule and am calling update on my schedule DAO to save the events. Here is my current code:

public Schedule update(Schedule schedule) {
    //first save the events
    for(Event event:schedule.getEvents()){
        getHibernateTemplate().saveOrUpdate(event); //<-Fails here
    }
    Schedule schedule2 = getHibernateTemplate().get(Schedule.class, schedule.getId());
    Schedule.copy(schedule, schedule2, false);
    System.err.println(schedule2.toString());
    getHibernateTemplate().saveOrUpdate(schedule2);
    return retrieveById(schedule2.getId());
}

All fields on my event are populated except the ID, which is auto generated. Here's the exception:

org.springframework.dao.DataIntegrityViolationException: could not insert: [com.heavyweightsoftware.leal.model.schedule.Event]; SQL [insert into EVENT (ID, END_TIME, EVENT_ID, EVENT_NAME, LOCATION, SCHEDULE_ID, START_TIME) values (default, ?, ?, ?, ?, ?, ?)]; constraint [FK3F47A7AA91E64F]; nested exception is org.hibernate.exception.ConstraintViolationException: could not insert: [com.heavyweightsoftware.leal.model.schedule.Event]
    at org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:637)
    at org.springframework.orm.hibernate3.HibernateAccessor.convertHibernateAccessException(HibernateAccessor.java:412)
    at org.springframework.orm.hibernate3.HibernateTemplate.doExecute(HibernateTemplate.java:411)
    at org.springframework.orm.hibernate3.HibernateTemplate.executeWithNativeSession(HibernateTemplate.java:374)
    at org.springframework.orm.hibernate3.HibernateTemplate.saveOrUpdate(HibernateTemplate.java:737)
    at com.heavyweightsoftware.leal.dao.hibernate.schedule.ScheduleHibernateDAO.update(ScheduleHibernateDAO.java:71)
    at com.heavyweightsoftware.leal.dao.hibernate.schedule.ScheduleHibernateDAO.update(ScheduleHibernateDAO.java:1)
    at com.heavyweightsoftware.leal.service.calendar.impl.CalendarServiceImpl.update(CalendarServiceImpl.java:168)
    at com.heavyweightsoftware.leal.service.calendar.impl.CalendarServiceImplTest.testGetCalendars(CalendarServiceImplTest.java:230)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:76)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: org.hibernate.exception.ConstraintViolationException: could not insert: [com.heavyweightsoftware.leal.model.schedule.Event]
    at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:96)
    at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
    at org.hibernate.id.insert.AbstractReturningDelegate.performInsert(AbstractReturningDelegate.java:63)
    at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2346)
    at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2853)
    at org.hibernate.action.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:71)
    at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:273)
    at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:320)
    at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:203)
    at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:129)
    at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:210)
    at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:195)
    at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:117)
    at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:93)
    at org.hibernate.impl.SessionImpl.fireSaveOrUpdate(SessionImpl.java:685)
    at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:677)
    at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:673)
    at org.springframework.orm.hibernate3.HibernateTemplate$16.doInHibernate(HibernateTemplate.java:740)
    at org.springframework.orm.hibernate3.HibernateTemplate.doExecute(HibernateTemplate.java:406)
    ... 30 more
Caused by: java.sql.SQLException: integrity constraint violation: foreign key no parent; FK3F47A7AA91E64F table: EVENT
    at org.hsqldb.jdbc.Util.sqlException(Util.java:215)
    at org.hsqldb.jdbc.JDBCPreparedStatement.fetchResult(JDBCPreparedStatement.java:4617)
    at org.hsqldb.jdbc.JDBCPreparedStatement.executeUpdate(JDBCPreparedStatement.java:308)
    at org.hibernate.id.IdentityGenerator$GetGeneratedKeysDelegate.executeAndExtract(IdentityGenerator.java:93)
    at org.hibernate.id.insert.AbstractReturningDelegate.performInsert(AbstractReturningDelegate.java:56)
    ... 46 more
Caused by: org.hsqldb.HsqlException: integrity constraint violation: foreign key no parent; FK3F47A7AA91E64F table: EVENT
    at org.hsqldb.error.Error.error(Error.java:131)
    at org.hsqldb.Constraint.getException(Constraint.java:898)
    at org.hsqldb.Constraint.checkInsert(Constraint.java:816)
    at org.hsqldb.StatementDML.performIntegrityChecks(StatementDML.java:1318)
    at org.hsqldb.StatementDML.insertRowSet(StatementDML.java:795)
    at org.hsqldb.StatementInsert.getResult(StatementInsert.java:139)
    at org.hsqldb.StatementDMQL.execute(StatementDMQL.java:190)
    at org.hsqldb.Session.executeCompiledStatement(Session.java:1294)
    at org.hsqldb.Session.execute(Session.java:956)
    at org.hsqldb.jdbc.JDBCPreparedStatement.fetchResult(JDBCPreparedStatement.java:4609)
    ... 49 more

Thanks! Heartbroken in Lexington:)

like image 469
Thom Avatar asked Feb 21 '23 02:02

Thom


1 Answers

Your problem is that you are trying to perform a join from your Schedule entity to your Event entity, when there is no foreign key relationship in that direction.

@OneToMany(cascade = CascadeType.ALL, fetch=FetchType.EAGER, orphanRemoval=true)
    @JoinColumn(name="ID")
private Collection<Event>   events;

With the above code you are instructing your JPA provider to retrieve all events for which the Schedule's id column matches with the primary key from Event. I'm pretty sure this is not what you intended. You should allow Event to define the mapping and then reference that from Schedule:

@OneToMany(cascade = CascadeType.ALL, fetch=FetchType.EAGER, mappedBy = "schedule")
private Collection<Event>   events;

Also, I would recommend using Sets to store your collections, since Hibernate has a known problem when storing multiple associations (bags) in an entity, unless you do.

like image 64
Perception Avatar answered Mar 05 '23 22:03

Perception