openjpa-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Fay Wang <>
Subject Re: @OneToMany/@ManyToOne, Bidirectional, Composite Key
Date Tue, 17 Jun 2008 02:15:15 GMT
Hi Ernico,

The cause of the problem is not the composite primary key but the  
mapping of the primary key column and join column in the child table:

(1) in the parent class TblScmpdt:
the primary key:  scmpdtId (the column: SCMPDT_ID)

(2) in the child class
the composite primary key: pdtbnfId (column: PDTBNF_ID)
                           scmpdtId (column: SCMPDT_ID)
the join column: SCMPDT_ID 

Please note that in this mapping, you have a primary key and the join value all mapped to
the column SCMPDT_ID in the child table.

In your test case:

TblScmpdt tblScmpdt = new TblScmpdt();  (1)
TblPdtbnf tblPdtbnf = new TblPdtbnf();  (2)   
TblScmpdt.addTblpdtbnf(tblPdtbnf);      (3)

Since you did not have the primary key set in the parent table (TblScmpdt ), openjpa will
regard this entity as a new one, and perform persist() on it even though you call merge().

The problem is in the child entity. In statement (3), you establish the 1-many relationship
between tblScmpdt and tblPdtbnf. The join value is therefore the primary key of tblScmpdt,
which is automatically generated by openjpa via table generator. However, since you did not
set the primary keys (pdtbnfId and scmpdtId, both are Integer class) for tblPdtbnf, they are
null values (the default values). When both the null value of scmpdtId primary key and the
non-null join value are set to column SCMPDT_ID, you got the following error message:

Caused by: <openjpa-1.0.0-r420667:568756 fatal user error>
org.apache.openjpa.persistence.InvalidStateException: Attempt to set column
"TBL_PDTBNF.SCMPDT_ID" to two different values: (null)"null", (class
java.lang.Integer)"700" This can occur when you fail to set both sides of a
two-sided relation between objects, or when you map different fields to the
same column, but you do not keep the values of these fields in synch.

This scenario can not be distinguished from the following one which is obviously a user-error
(note Statement (2.1)):

TblScmpdt tblScmpdt = new TblScmpdt();  (1)
TblPdtbnf tblPdtbnf = new TblPdtbnf();  (2)   
tblPdtbnf.setScmpdtId(null);            (2.1)
TblScmpdt.addTblpdtbnf(tblPdtbnf);      (3)

This problem can be fixed by not using the primary key column as the join column. Specifically,
setting the join-column name to something other than  
SCMPDT_ID should solve this problem:

@ManyToOne(fetch = FetchType.LAZY,cascade=CascadeType.MERGE)
@JoinColumn(name = "XX_ID",referencedColumnName="SCMPDT_ID")
private TblScmpdt tblScmpdt;

If you really want to use the primary key column as the join column, then don't let openjpa
to automatically generate the primary key, so that you can explicitly set the primary keys
of the child class the same as the join value. If you really want openjpa to automatically
generate primary key, then you have to use the "lousy" way you described in your earlier email.
Please let me know what you think. Thanks!


--- On Sat, 6/14/08, Enrico Goosen <> wrote:

> From: Enrico Goosen <>
> Subject: Re: @OneToMany/@ManyToOne, Bidirectional, Composite Key
> To:
> Date: Saturday, June 14, 2008, 5:46 AM
> Hi Fay,
> The primary key for TblScmpdt is database generated.
> Here's the mapping:
> @TableGenerator(name="baseGenerator",schema="EBSTATUS",table="TBL_KEYGEN",pkColumnName="PRIMARY_KEY_COLUMN"
> ,valueColumnName="LAST_USED_ID",pkColumnValue="TBL_SCMPDT_ID",allocationSize=100)
> @Id
> @GeneratedValue(strategy=GenerationType.TABLE,generator="baseGenerator")
> @Column(name = "SCMPDT_ID",nullable=false)
> private Integer scmpdtId; 
> As I mentioned in my previous post, the code works (no
> exceptions), but its
> flawed because of the bug in JPA when performing a cascade
> persist on a
> OneToMany entity where the child (many) entity has a
> composite key.
> I should simply be able to do the following:
> TblScmpdt tblScmpdt = new TblScmpdt(); //new
> (non-persistent) parent entity
> //set fields on tblScmpdt ...
> TblPdtbnf tblPdtbnf = new TblPdtbnf(); //new
> (non-persistent) child entity
> //set fields on tblPdtbnf ...
> tblScmpdt.addTblpdtbnf(tblPdtbnf); //see method below,
> which sets the parent
> referrence on child
> //TblScmpdt method:
> public void addTblPdtbnf(TblPdtbnf tblPdtbnf) {
> 	tblPdtbnf.setTblScmpdt(this); //need to set both sides of
> bidirectional
> relationship
> 	getTblPdtbnfs().add(tblPdtbnf);
> }
> //Now I should be able to persist parent and cascade
> persist child
> automatically according to JPA docs
> tblScmpdt = em.merge(tblScmpdt); 
> ...but unfortunately, the above doesn't work.
> I have to merge/persist the parent first > then get the
> ID of the newly
> persisted parent and set it on the new child > then add
> the child to the
> parent > then merge the parent again. Tedious!
> Do you understand the problem?
> Regarding TblPdtbnfcde, this is a OneToOne reference on
> TblPdtbnf.
> TblPdtbnf's composite primary key is made up of
> TblPdtbnfcde.pdtbnfId and
> TblScmpdt.scmpdtId
> By the way, cascade persist works fine on my other
> OneToMany classes where
> there isn't a composite key.
> So this is definitely a bug.
> Enrico,
>     What is the primary key field in the TblScmpdt entity?
> Did you set
> primary key for tblScmpdt before calling merge? I made an
> integer primary
> key field in TblScmpdt, and set the primary key to 1 in
> tblScmpdt before
> calling merge, and your test code works fine for me (I also
> omit
> TblPdtbnfcde in your test code for lack of detailed
> information). If you
> already set the primary key and still get the error, please
> specify more
> detail of your TblScmpdt class.     
> -f
> -- 
> View this message in context:
> Sent from the OpenJPA Users mailing list archive at


View raw message