You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@openjpa.apache.org by Christian Defoy <ch...@gmail.com> on 2007/07/25 20:56:13 UTC

OpenJPA is not inserting the parent reference on update

Hello,

For some reason, I am unable to update an object that is already
persisted.  Here's how it goes:

I have a Shape object that includes an Attachment.  This is already
saved in the database.  I update the Shape by replacing its Attachment
object with a new one that contains a Note object:

        manager.getTransaction().begin();
        Shape loadedBase = manager.find( Shape.class, 18 );

        // Create new attachment
        Attachment newAttach = new Attachment();
        newAttach.setValue( "attachment 2" );
        Note note = new Note();
        note.setText( "note text" );
        note.setParent( newAttach );
        newAttach.setNote( note );

        newAttach.setParent( loadedBase );
        loadedBase.setAttachment( newAttach );
        manager.getTransaction().commit();

Upon commiting this transaction, I see the following statements:

INSERT INTO NOTE (NOTE_TEXT) VALUES (?) [params=(String) note text]
INSERT INTO ATTACH (SHAPE_ID, VALUE) VALUES (?, ?) [params=(int) 12,
(String) attachment 2]
CALL IDENTITY()
DELETE FROM ATTACH WHERE ATTACH_ID = ? [params=(int) 44]
UPDATE NOTE SET PARENT_ID = ? WHERE NOTE_ID = ? [params=(int) 45, (int) 0]

The first statement in the list throws an exception as Note must
provide a parent:

Attempt to insert null into a non-nullable column: column: PARENT_ID
table: NOTE in statement [INSERT INTO NOTE (NOTE_TEXT) VALUES (?)]
{prepstmnt 11544872 INSERT INTO NOTE (NOTE_TEXT) VALUES (?)
[params=(String) note text]} [code=-10, state=23000]

What am I doing wrong?

I am able to get the transaction to commit properly by either
- setting PROPERTY access on the Note object;
- detaching the Shape object before updating it and calling merge();
- starting my transaction once my new Attachment object is created and
Note object is set;
- stepping inside the code using Eclipse.

In all cases, the Attachment object is inserted first and then the
Note object is inserted with a reference to the Attachment.

Thanks in advance!

Christian

-----

@Entity
@Table(name="SHAPE")
public class Shape
{
    @Column(name="shape_id")
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private int id;

    private String name;

    @OneToOne( mappedBy="parent", cascade=CascadeType.ALL,
fetch=FetchType.EAGER )
    @Dependent
    private Attachment attachment;

    // Getters and setters are trivial
}

@Entity
@Table( name="attach" )
public class Attachment
{
    @Id
    @GeneratedValue( strategy=GenerationType.IDENTITY )
    @Column( name="attach_id" )
    private int id;

    @OneToOne( cascade=CascadeType.ALL, fetch=FetchType.LAZY )
    @Column( name="shape_id" )
    private Shape parent;

    private String value;

    @OneToOne( mappedBy="parent", cascade=CascadeType.ALL )
    private Note note;

    // Getters and setters are trivial
}

@Entity
@Table( name="note" )
public class Note
{
    @Id
    @GeneratedValue( strategy=GenerationType.IDENTITY )
    @Column( name="note_id" )
    private int id;

    @OneToOne( optional=false )
    @Column( name="parent_id" )
    private Attachment parent;

    @Column( name="note_text", length=20 )
    private String text;

    // Getters and setters are trivial
}

Re: OpenJPA is not inserting the parent reference on update

Posted by Christian Defoy <ch...@gmail.com>.
Hi!

I managed to get around the problem by invoking manager.remove() on my
Attachment object before replacing it with the one.  It seems to work
so far...

Prior to that, I was almost successfull by detaching my Shape object
prior to replacing its Attachment object.  But then, when the
Attachment object was deleted (marked with @Dependent), it sometimes
came before the Note objects and since there is a cascade delete in
the db, an exception was thrown for optimistic lock failure...

Christian

Re: OpenJPA is not inserting the parent reference on update

Posted by Christian Defoy <ch...@gmail.com>.
Hi Patrick,

I am using Hypersonic verswion 1.8.0.4.

Here is the persistence.xml.

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    version="1.0">

<persistence-unit name="basic" transaction-type="RESOURCE_LOCAL">

   <class>ex3.Shape</class>
   <class>ex3.Attachment</class>
   <class>ex3.Note</class>

   <properties>
      <property name="openjpa.Log" value="DefaultLevel=INFO, SQL=TRACE"/>
      <property name="openjpa.ConnectionRetainMode" value="always"/>
      <property name="openjpa.ConnectionUserName" value="sa"/>
      <property name="openjpa.ConnectionPassword" value=""/>
      <property name="openjpa.ConnectionURL"
value="jdbc:hsqldb:hsql://localhost/jpa-db"/>
      <property name="openjpa.ConnectionDriverName"
value="org.hsqldb.jdbcDriver"/>
  <property name="openjpa.FetchBatchSize" value="-1" />
  <property name="openjpa.jdbc.SchemaFactory"
value="native(ForeignKeys=true)" />
   </properties>
</persistence-unit>
</persistence>


Hope this sheds some light on the problem!

Christian

On 7/25/07, Patrick Linskey <pl...@gmail.com> wrote:
> Hi,
>
> It sounds like a foreign key ordering problem. What db are you using?
> Can you post your persistence.xml properties?
>
> -Patrick
>
> On 7/25/07, Christian Defoy <ch...@gmail.com> wrote:
> > Hello,
> >
> > For some reason, I am unable to update an object that is already
> > persisted.  Here's how it goes:
> >
> > I have a Shape object that includes an Attachment.  This is already
> > saved in the database.  I update the Shape by replacing its Attachment
> > object with a new one that contains a Note object:
> >
> >        manager.getTransaction().begin();
> >        Shape loadedBase = manager.find( Shape.class, 18 );
> >
> >        // Create new attachment
> >        Attachment newAttach = new Attachment();
> >        newAttach.setValue( "attachment 2" );
> >        Note note = new Note();
> >        note.setText( "note text" );
> >        note.setParent( newAttach );
> >        newAttach.setNote( note );
> >
> >        newAttach.setParent( loadedBase );
> >        loadedBase.setAttachment( newAttach );
> >        manager.getTransaction().commit();
> >
> > Upon commiting this transaction, I see the following statements:
> >
> > INSERT INTO NOTE (NOTE_TEXT) VALUES (?) [params=(String) note text]
> > INSERT INTO ATTACH (SHAPE_ID, VALUE) VALUES (?, ?) [params=(int) 12,
> > (String) attachment 2]
> > CALL IDENTITY()
> > DELETE FROM ATTACH WHERE ATTACH_ID = ? [params=(int) 44]
> > UPDATE NOTE SET PARENT_ID = ? WHERE NOTE_ID = ? [params=(int) 45, (int) 0]
> >
> > The first statement in the list throws an exception as Note must
> > provide a parent:
> >
> > Attempt to insert null into a non-nullable column: column: PARENT_ID
> > table: NOTE in statement [INSERT INTO NOTE (NOTE_TEXT) VALUES (?)]
> > {prepstmnt 11544872 INSERT INTO NOTE (NOTE_TEXT) VALUES (?)
> > [params=(String) note text]} [code=-10, state=23000]
> >
> > What am I doing wrong?
> >
> > I am able to get the transaction to commit properly by either
> > - setting PROPERTY access on the Note object;
> > - detaching the Shape object before updating it and calling merge();
> > - starting my transaction once my new Attachment object is created and
> > Note object is set;
> > - stepping inside the code using Eclipse.
> >
> > In all cases, the Attachment object is inserted first and then the
> > Note object is inserted with a reference to the Attachment.
> >
> > Thanks in advance!
> >
> > Christian
> >
> > -----
> >
> > @Entity
> > @Table(name="SHAPE")
> > public class Shape
> > {
> >    @Column(name="shape_id")
> >    @Id
> >    @GeneratedValue(strategy=GenerationType.IDENTITY)
> >    private int id;
> >
> >    private String name;
> >
> >    @OneToOne( mappedBy="parent", cascade=CascadeType.ALL,
> > fetch=FetchType.EAGER )
> >    @Dependent
> >    private Attachment attachment;
> >
> >    // Getters and setters are trivial
> > }
> >
> > @Entity
> > @Table( name="attach" )
> > public class Attachment
> > {
> >    @Id
> >    @GeneratedValue( strategy=GenerationType.IDENTITY )
> >    @Column( name="attach_id" )
> >    private int id;
> >
> >    @OneToOne( cascade=CascadeType.ALL, fetch=FetchType.LAZY )
> >    @Column( name="shape_id" )
> >    private Shape parent;
> >
> >    private String value;
> >
> >    @OneToOne( mappedBy="parent", cascade=CascadeType.ALL )
> >    private Note note;
> >
> >    // Getters and setters are trivial
> > }
> >
> > @Entity
> > @Table( name="note" )
> > public class Note
> > {
> >    @Id
> >    @GeneratedValue( strategy=GenerationType.IDENTITY )
> >    @Column( name="note_id" )
> >    private int id;
> >
> >    @OneToOne( optional=false )
> >    @Column( name="parent_id" )
> >    private Attachment parent;
> >
> >    @Column( name="note_text", length=20 )
> >    private String text;
> >
> >    // Getters and setters are trivial
> > }
> >
>
>
> --
> Patrick Linskey
> 202 669 5907
>

Re: OpenJPA is not inserting the parent reference on update

Posted by Patrick Linskey <pl...@gmail.com>.
Hi,

It sounds like a foreign key ordering problem. What db are you using?
Can you post your persistence.xml properties?

-Patrick

On 7/25/07, Christian Defoy <ch...@gmail.com> wrote:
> Hello,
>
> For some reason, I am unable to update an object that is already
> persisted.  Here's how it goes:
>
> I have a Shape object that includes an Attachment.  This is already
> saved in the database.  I update the Shape by replacing its Attachment
> object with a new one that contains a Note object:
>
>        manager.getTransaction().begin();
>        Shape loadedBase = manager.find( Shape.class, 18 );
>
>        // Create new attachment
>        Attachment newAttach = new Attachment();
>        newAttach.setValue( "attachment 2" );
>        Note note = new Note();
>        note.setText( "note text" );
>        note.setParent( newAttach );
>        newAttach.setNote( note );
>
>        newAttach.setParent( loadedBase );
>        loadedBase.setAttachment( newAttach );
>        manager.getTransaction().commit();
>
> Upon commiting this transaction, I see the following statements:
>
> INSERT INTO NOTE (NOTE_TEXT) VALUES (?) [params=(String) note text]
> INSERT INTO ATTACH (SHAPE_ID, VALUE) VALUES (?, ?) [params=(int) 12,
> (String) attachment 2]
> CALL IDENTITY()
> DELETE FROM ATTACH WHERE ATTACH_ID = ? [params=(int) 44]
> UPDATE NOTE SET PARENT_ID = ? WHERE NOTE_ID = ? [params=(int) 45, (int) 0]
>
> The first statement in the list throws an exception as Note must
> provide a parent:
>
> Attempt to insert null into a non-nullable column: column: PARENT_ID
> table: NOTE in statement [INSERT INTO NOTE (NOTE_TEXT) VALUES (?)]
> {prepstmnt 11544872 INSERT INTO NOTE (NOTE_TEXT) VALUES (?)
> [params=(String) note text]} [code=-10, state=23000]
>
> What am I doing wrong?
>
> I am able to get the transaction to commit properly by either
> - setting PROPERTY access on the Note object;
> - detaching the Shape object before updating it and calling merge();
> - starting my transaction once my new Attachment object is created and
> Note object is set;
> - stepping inside the code using Eclipse.
>
> In all cases, the Attachment object is inserted first and then the
> Note object is inserted with a reference to the Attachment.
>
> Thanks in advance!
>
> Christian
>
> -----
>
> @Entity
> @Table(name="SHAPE")
> public class Shape
> {
>    @Column(name="shape_id")
>    @Id
>    @GeneratedValue(strategy=GenerationType.IDENTITY)
>    private int id;
>
>    private String name;
>
>    @OneToOne( mappedBy="parent", cascade=CascadeType.ALL,
> fetch=FetchType.EAGER )
>    @Dependent
>    private Attachment attachment;
>
>    // Getters and setters are trivial
> }
>
> @Entity
> @Table( name="attach" )
> public class Attachment
> {
>    @Id
>    @GeneratedValue( strategy=GenerationType.IDENTITY )
>    @Column( name="attach_id" )
>    private int id;
>
>    @OneToOne( cascade=CascadeType.ALL, fetch=FetchType.LAZY )
>    @Column( name="shape_id" )
>    private Shape parent;
>
>    private String value;
>
>    @OneToOne( mappedBy="parent", cascade=CascadeType.ALL )
>    private Note note;
>
>    // Getters and setters are trivial
> }
>
> @Entity
> @Table( name="note" )
> public class Note
> {
>    @Id
>    @GeneratedValue( strategy=GenerationType.IDENTITY )
>    @Column( name="note_id" )
>    private int id;
>
>    @OneToOne( optional=false )
>    @Column( name="parent_id" )
>    private Attachment parent;
>
>    @Column( name="note_text", length=20 )
>    private String text;
>
>    // Getters and setters are trivial
> }
>


-- 
Patrick Linskey
202 669 5907