Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
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 12:13 Go to next message
Jason Hodge is currently offline 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 11:09 Go to previous messageGo to next message
James Sutherland is currently offline James Sutherland
Messages: 1939
Registered: July 2009
Location: Ottawa, Canada
Senior Member

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 13:19 Go to previous messageGo to next message
Jason Hodge is currently offline 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 #846691 is a reply to message #846685] Mon, 16 April 2012 14:04 Go to previous messageGo to next message
Jason Hodge is currently offline Jason Hodge
Messages: 7
Registered: April 2012
Junior Member
And just a reminder, many of our list-of-value-like, bottom-tier objects (in our persistent object graph) are manifesting the same errant behavior. I'm sure that's a hint as to what is wrong.
Re: PK Violation on Many-to-One Child Record [message #849817 is a reply to message #846691] Thu, 19 April 2012 09:28 Go to previous messageGo to next message
James Sutherland is currently offline James Sutherland
Messages: 1939
Registered: July 2009
Location: Ottawa, Canada
Senior Member

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
Re: PK Violation on Many-to-One Child Record [message #850093 is a reply to message #842801] Thu, 19 April 2012 15:00 Go to previous messageGo to next message
Jason Hodge is currently offline Jason Hodge
Messages: 7
Registered: April 2012
Junior Member
If I use EJB3, can I use @Remote on Session Beans, or do I need to use @Local in order to ensure no serialization?
Re: PK Violation on Many-to-One Child Record [message #854097 is a reply to message #850093] Mon, 23 April 2012 13:03 Go to previous message
James Sutherland is currently offline James Sutherland
Messages: 1939
Registered: July 2009
Location: Ottawa, Canada
Senior Member

You can use either. But if you use @Remote, or if you span multiple transactions you must merge the detached object using merge() or using find() and manually merging your changes.


James : Wiki : Book : Blog : Twitter
Previous Topic:Outer Join with 3 tables is not working
Next Topic:Const Mapping
Goto Forum:
  


Current Time: Fri Jul 11 14:13:10 EDT 2014

Powered by FUDForum. Page generated in 0.05288 seconds