openjpa-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Pinaki Poddar (JIRA)" <j...@apache.org>
Subject [jira] Commented: (OPENJPA-245) Attach NEW and auto-increment identity
Date Tue, 29 May 2007 22:43:15 GMT

    [ https://issues.apache.org/jira/browse/OPENJPA-245?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#action_12499951
] 

Pinaki Poddar commented on OPENJPA-245:
---------------------------------------

>From openjpa documentation (ref: 1.2.  Attach Behavior)

"  * If the instance was detached and detached state is enabled, OpenJPA will use the detached
state to determine the object's version and primary key values. In addition, this state will
tell OpenJPA which fields were loaded at the time of detach, and in turn where to expect changes.
Loaded detached fields with null values will set the attached instance's corresponding fields
to null.

    * If the instance has a Version field, OpenJPA will consider the object detached if the
version field has a non-default value, and new otherwise.
   * If neither of the above cases apply, OpenJPA will check to see if an instance with the
same primary key values exists in the database. If so, the object is considered detached.
Otherwise, it is considered new."

The implementaion does not seem to adhere to the last statement above. This is observed by
the original scenario described in this issue as well as the attached testcase testMergeUnversionedNewObjectCreatesNewRecord().


AttachStrategy implementaion is responsible for merge().  For a newly created entity instance
even if it carries id of a persistent record -- the  attach strategy selected (by AttachManager.getStrategy()
method) is VersionAttachStrategy. Now, VersionAttachStrategy determines whether the instance
to be attached is new by the following logic:

boolean isNew = !broker.isDetached(pc); // VersionAttachStrategy.java:70

which turns out to be true in this case. 

With the current implementation, VersionAttachStrategy does not detect that a) the instance
to be attached is carrying a primary key equal to a pre-existing data record and b) hence
it should be an update and not an insert. However, it passes the instance as PNEW further
downstream to be flushed (the instance is still carrying a primary key value same as the one
set by the application and a record with the same key exists). However, as the identity field
is annotated with GenerateValue.IDENTITY -- the PNEW instance gets stored without a duplicate
key exception and its primary key in the database is auto incremented. That the primary key
value assigned by the user application is ignored and a new value is assigned can also be
verified (see the testcase).     

This is the flow for a new instance being merged in a context which is not managing another
instance with the same primary key. If the new instance carrying an existing key was merged
to a EntityManager that already is managing another instance, because the attach strategy
still considered the to be merged instance as PNEW -- a EntityExistsException is raised by
the object management kernel even before attampting a flush to the database.

> Attach NEW and auto-increment identity
> --------------------------------------
>
>                 Key: OPENJPA-245
>                 URL: https://issues.apache.org/jira/browse/OPENJPA-245
>             Project: OpenJPA
>          Issue Type: Bug
>          Components: jpa
>    Affects Versions: 0.9.6, 0.9.7
>         Environment: jdk1.5.0_11, Win XP, Fedora Core 6, Postgres 8.1 (on Fedora)
>            Reporter: Aleksandar Likic
>         Attachments: TestMerge.zip
>
>
> According to documentation (1.2 Attach Behavior), when an entity instance is NEW (never
detached):
>     * If neither of the above cases apply, OpenJPA will check to see if an instance with
the same primary key values exists in the database. If so, the object is considered detached.
Otherwise, it is considered new.
> This doesn't work for me - a new record in database is created on commit instead of updating
the existing one. The "regular" case - detach/modify/attach works fine - the existing record
is updated.
> It is very easy to reproduce - just create a new instance of an entity, assign an already
existing primary key, call em.merge() and commit. A new record will be created in database,
with new, auto-generated primary key.
> I stumbled on this trying to implement a web service that uses OpenJPA-based backend.
When servicing an "update" request, the web service instantiates a NEW object (by performing
XML de-serialization) and calls em.merge to update the entity. A new record gets created instead
of updating an existing one.
> ------------ Entity class (START) ------------------------------
> package exaple;
> public class Consumer implements java.io.Serializable {
>   private long id;
>   public long getId() {
>     return this.id;
>   }
>   public void setId(long id) {
>     this.id = id;
>   }
>   private java.lang.String firstName;
>   public java.lang.String getFirstName() {
>     return this.firstName;
>   }
>   public void setFirstName(java.lang.String firstName) {
>     this.firstName = firstName;
>   }
>   private java.lang.String lastName;
>   public java.lang.String getLastName() {
>     return this.lastName;
>   }
>   public void setLastName(java.lang.String lastName) {
>     this.lastName = lastName;
>   }
> ------------ Entity class (END) ------------------------------
> ------------ persistence.xml (START) ------------------------------
> <?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="example" transaction-type="RESOURCE_LOCAL">
>     
>         <provider>org.apache.openjpa.persistence.PersistenceProviderImpl</provider>
>         <!-- We must enumerate each entity in the persistence unit -->
>         <class>example.Consumer</class>
>         <properties>
>             <property name="openjpa.jdbc.DBDictionary" value="postgres"/>
>             <property name="openjpa.ConnectionDriverName" value="org.postgresql.Driver"/>
>             <property name="openjpa.ConnectionUserName" value="app_user"/>
>             <property name="openjpa.ConnectionPassword" value="app_user"/>
>             <property name="openjpa.ConnectionURL" value="jdbc:postgresql://localhost/alikic"/>
>             <property name="openjpa.Log" value="DefaultLevel=WARN,SQL=TRACE"/>
>             
>         </properties>
>     </persistence-unit>
>     
> </persistence>
> ------------ persistence.xml (END) ------------------------------
> ------------ orm.xml (START) ------------------------------
> <entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm" 
>     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
>     xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm orm_1_0.xsd"
>     version="1.0">
>     <entity class="example.Consumer">
>         <attributes>
>             <id name="id">
>                 <generated-value strategy="IDENTITY"/>
>             </id>
>             <basic name="firstName">
>                 <column name="first_name"/>
>             </basic>
>             <basic name="lastName">
>                 <column name="last_name"/>
>             </basic>
>         </attributes>
>     </entity>
> </entity-mappings>
> ------------ orm.xml (END) ------------------------------

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.


Mime
View raw message