I have two entities and an embeddable class (the below was stripped down from the real classes I'm using):
@Entity
public class LogProperty {
@Id @GeneratedValue @Column( name="propertyId" )
private Integer id;
}
@Embeddable
public class PropertyValue
{
@Basic @Column( length=500, name="propertyValue" )
private String value;
@Temporal( TemporalType.TIMESTAMP ) @Column( name="propertyDateValue" )
private Date dateValue;
}
@Entity
public class Event {
@Id @GeneratedValue @Column( name="eventId" )
private Integer id;
@ElementCollection
@CollectionTable( name="eventProperty",
joinColumns=@JoinColumn( name="eventId", nullable=false ) )
@MapKeyJoinColumn( name="propertyId", nullable=false )
private Map<LogProperty, PropertyValue> properties;
}
When I create an Event object and populate properties, EclipseLink tries to insert the Event's row before it inserts the LogProperty's row:
--PERSIST operation called on: LogProperty(3, status).
--PERSIST operation called on: Event(1, EventType(1, EventTypeGroup(1, asset), statusChanged), Fri Dec 17 00:00:00 AST 2010).
--begin unit of work commit
--begin transaction
--reconnecting to external connection pool
--Execute query InsertObjectQuery(Event(1, EventType(1, EventTypeGroup(1, asset), statusChanged), Fri Dec 17 00:00:00 AST 2010))
--INSERT IGNORE INTO sysLog.event (eventId, DATEOCCURRED, parentEventId, loginId, eventTypeId) VALUES (?, ?, ?, ?, ?)
bind => [1, 2010-12-17 00:00:00.0, null, 1, 1]
--Execute query InsertObjectQuery(PropertyValue(value=blah, dateValue=null))
--INSERT IGNORE INTO sysLog.eventProperty (eventId, propertyValue, propertyDateValue, propertyId) VALUES (?, ?, ?, ?)
bind => [1, blah, null, 3]
--ClientSession(1805807281)--Thread(Thread[main,5,main])--CALL 1
--Local Exception Stack:
Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.1.2.v20101206-r8635): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLException: integrity constraint violation: foreign key no parent; FK53077A8F3C4745BD table: EVENTPROPERTY
Error Code: -177
Call: INSERT IGNORE INTO sysLog.eventProperty (eventId, propertyValue, propertyDateValue, propertyId) VALUES (?, ?, ?, ?)
bind => [1, blah, null, 3]
Query: InsertObjectQuery(PropertyValue(value=blah, dateValue=null))
at org.eclipse.persistence.exceptions.DatabaseException.sqlException(DatabaseException.java:324)
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeDirectNoSelect(DatabaseAccessor.java:797)
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeNoSelect(DatabaseAccessor.java:863)
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.basicExecuteCall(DatabaseAccessor.java:583)
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeCall(DatabaseAccessor.java:526)
(wow that's a big stack trace)
A couple of things I'd like to point out:
- I tried to make an isolated test case, but couldn't reproduce it. I DID, however, notice that EclipseLink DIDN'T create a foreign key between the eventProperty.propertyId FK and the property.propertyId PK. It only created the foreign key between eventProperty.eventId and event.eventId.
- I've encountered this problem everywhere else in my project where I have this pattern.
- It handles other dependencies in the Event entity, like EventType (not included in my example Java, but included in the logging output).
- Even though I called em.persist() in an order that would have satisfied dependencies (i.e. I persisted LogProperty first, THEN persisted Event, as the logs show), EclipseLink jumped the gun and tried to insert the Event object first.
Is the pattern I used for my mapping incorrect, am I missing something, or could this be a bug with relational dependency ordering?
Thanks,
Scott