Home » Eclipse Projects » EclipseLink » PK Violation on Many-to-One Child Record(Child is not changed, but is being persisted with PK violation)
PK Violation on Many-to-One Child Record [message #842801] |
Thu, 12 April 2012 16:13 |
Jason Hodge Messages: 7 Registered: April 2012 |
Junior Member |
|
|
I have an entity, Journal, which has a Many-to-One relationship with a second entity, DeliveryType. The mapping is expressed as:
@Entity
@Table(name = "JOURNAL")
public class Journal implements Serializable, Comparable<Journal> {
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "DELIVERY_TYPE_ID")
private DeliveryType deliveryType;
//...excluded...
}
DeliveryType is merely a static look-up table with 6 values. It should never be persisted. Its ID should just be written as a foreign key to the Journal table.
@Entity
@Table(name="DELIVERY_TYPE")
@NamedQueries({
@NamedQuery(name=DeliveryType.DISPLAYABLE,
query="select s from DeliveryType s where s.isDisplayable = 'Y'" ),
@NamedQuery(name=DeliveryType.DUPE_CHECK,
query="select s from DeliveryType s where lower(s.description)=lower(:description)" )
})
public class DeliveryType implements Serializable, Comparable<DeliveryType> {
//...omitted...
}
The project previously used TopLink, but I don't think the conversion is responsible for the odd behavior. The problem is that when parent entity, Journal is changed (assigned a different DeliveryType), EclipseLink seems to think that the DeliveryType object is a brand new object and does an INSERT op on it, causing a primary key violation. This is suddenly happening with many of our look-up-only entities.
Is there some kind of caching going on that detaches these entities from the PersistenceManager somehow? Why does EclipseLink think they are new and try to save them?
Details:
===============
EclipseLink 2.3
JPA 2.0
JDeveloper
WebLogic 10.3.5
Oracle 9, Thin Driver, Non-XA DataSources
Sun JDK 1.6
|
|
|
Re: PK Violation on Many-to-One Child Record [message #846668 is a reply to message #842801] |
Mon, 16 April 2012 15:09 |
|
That is odd, but what you are doing does not sound good.
Corrupting a managed object by making it reference a detached object is not normally a good idea. Managed objects should normally only refer to other managed objects.
If the DeliveryType is truly read-only, you could just mark it as @ReadOnly.
Otherwise, you could use find() or getReference() to get the correct managed instance of the object.
Not sure how this was working before. How do you set the DeliveryType, are you using merge()? Was you cascade setting different before? It is odd that it is doing an insert, as you do not have cascade persist set, I would expect an error, or having it ignored.
James : Wiki : Book : Blog : Twitter
|
|
|
Re: PK Violation on Many-to-One Child Record [message #846685 is a reply to message #846668] |
Mon, 16 April 2012 17:19 |
Jason Hodge Messages: 7 Registered: April 2012 |
Junior Member |
|
|
James,
Thanks so much for taking the time to look at this for me!!
Sorry to give the wrong impression. The DeliveryType IS a managed object. It is loaded from the table of just 6 rows, and referenced from the Journal object. The relationship graph being persisted is:
Case
--Journal
--DeliveryType
--Journal
--DeliveryType
--Journal
--DeliveryType
--Journal
--DeliveryType
So a single case is persisted. A case can have many Journal entries. Each Journal Entry has just 1 required DeliveryType, which is assigned from just 6 possible values (such as FAX, HAND DELIVERY, etc). The question is, when we call:
entityManager.persist(case);
Why is it saving Case, Saving each Journal, and trying to insert the DeliveryType object into the database as though they are entirely new objects?
Here is the error console output.
Query: WriteObjectQuery(com.whatever.DeliveryType@855b9a)],numRepliesOwedMe=0,numRepliesOwedOthers=0,seconds since begin=1,seconds left=30,XAServerResourceInfo[my_app_DefaultDomain]=(ServerResourceInfo[my_app_DefaultDomain]=(state=rolledback,assigned=DefaultServer),xar=weblogic.jdbc.wrapper.JTSEmulateXAResourceImpl@9df864,re-Registered = false),SCInfo[DefaultDomain+DefaultServer]=(state=rolledback),properties=({weblogic.transaction.name=[EJB com.whatever.service.CaseSessionBean.saveAndReopen()], weblogic.jdbc.remote.my_app=t3://10.10.1.1:7101}),OwnerTransactionManager=ServerTM[ServerCoordinatorDescriptor=(CoordinatorURL=DefaultServer+10.10.1.1:7101+DefaultDomain+t3+, XAResources={my_app_DefaultDomain, document_storage_app_DefaultDomain, WSATGatewayRM_DefaultServer_DefaultDomain},NonXAResources={})],CoordinatorURL=DefaultServer+10.10.1.1:7101+DefaultDomain+t3+): weblogic.transaction.RollbackException: Unexpected exception in beforeCompletion: sync=org.eclipse.persistence.transaction.JTASynchronizationListener@1ad09a1
Internal Exception: java.sql.SQLIntegrityConstraintViolationException: ORA-00001: unique constraint (MY_DATA.DELIVERY_TYPE_PK) violated
Error Code: 1
Call: INSERT INTO my_data.DELIVERY_TYPE (DELIVERY_TYPE_ID, DESCRIPTION, DISPLAYABLE) VALUES (?, ?, ?)
bind => [2, FAX, Y]
The essential entity code and annotations are as so:
// Case to Journal
@Entity
@Table(name = "CASE")
@NamedStoredProcedureQuery(
name="PROCESS_CASE_PROCEDURE",
procedureName="processCase",
returnsResultSet=false,
parameters={
@StoredProcedureParameter(queryParameter="param1",name="x",direction=Direction.OUT,type=String.class)
}
)
public class Case implements Serializable, Comparable<EoasCase> {
@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.PERSIST)
@JoinColumn(name = "CASE_ID" )
@OrderBy("entryDate")
private List<Journal> journals = new ArrayList<Journal>();
}
@Entity
@Table(name = "JOURNAL")
public class Journal implements Serializable, Comparable<Journal> {
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "DELIVERY_TYPE_ID")
private DeliveryType deliveryType;
}
@Entity
@Table(name="DELIVERY_TYPE")
@NamedQueries({
@NamedQuery(name=DeliveryType.DISPLAYABLE,
query="select s from DeliveryType s where s.isDisplayable = 'Y'" ),
@NamedQuery(name=DeliveryType.DUPE_CHECK,
query="select s from DeliveryType s where lower(s.description)=lower(:description)" )
})
public class DeliveryType implements Serializable, Comparable<DeliveryType> {
}
Is it possible that rather than swapping out which DeliveryType object is associated with a Journal, the application, rather is trying to modify the DeliveryType object that is ALREADY associated with the Journal? Even if it was, it should trigger an UPDATE, not an INSERT, right?
Again, thanks for your help!
|
|
| |
Re: PK Violation on Many-to-One Child Record [message #849817 is a reply to message #846691] |
Thu, 19 April 2012 13:28 |
|
If an object is existing, you cannot just create a new object for it, or use a detached one from another context or that has been serialized. You need to use the managed instance from the current context (EntityManager). You must use find() to get this managed instance, and edit this instance if you wish to have it updated.
Perhaps include the code you use to persist the object.
James : Wiki : Book : Blog : Twitter
|
|
| | |
Goto Forum:
Current Time: Sun Sep 22 13:09:38 GMT 2024
Powered by FUDForum. Page generated in 0.04141 seconds
|