Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
[eclipselink-users] Tree hieararchy and @PrivateOwned problems

Please can you tell me what I'm doing wrong. Or I there is bug in eclipselink version (stable 2.1.1 - nightly 2.2.0.v20101002-r8292).

I store categories with entity list in tree hierarchy. (stripped code attached).
I want move one category to another so only category parent should be changed (= 1x UPDATE sql statement)

Category_1
  +- Category_2
  +- Category_3

Action: move Category_2 to Category_3

EclipseLink steps:
*) remove Category_2 from Category_1
   - delete Category_2
   - cascade delete all entities from Category_2 (@PrivateOwned)
*) add Category_2 to Category_3
   - undelete Category_2
   - cascade undelete all entities from Category_2 (@PrivateOwned)  --- here is problem !!!
   - record modify Category_2 parent, Category_3 children
 

2 different cases for @PrivateOwned entities

1)  @OneToMany(mappedBy = "category", cascade = {})
When I want to move Category_2 to Category_3 (should one generate SQL UPDATE statement) entities from Category 2 are ALWAYS deleted.

2) @OneToMany(mappedBy = "category", cascade = {CascadeType.MERGE, CascadeType.REFRESH, CascadeType.PERSIST})
        or
   @OneToMany(mappedBy = "category", cascade = CascadeType.ALL)

Is non deterministic. Sometimes it deletes all entities from Category_2. (generates 1x UPDATE, 2x DELETE) sometimes only 1x UPDATE that is supposed to be correct behaviour.

----

I think that there is bug in @PrivateOwned implementation. Non determinism in case 2) is due to using Map for storing modifications in UOW. Map uses hashCode and identityHashCode - so the order of modifications in UOW is changing.
Sometimes it uses "cascade" and sometimes it uses "@PrivateOwned" part of implementation.

In @PrivateOwned case 1) Category_2 is undeleted from UOW (UnitOfWorkImpl:4171) bud entities remain in deleted collection.

https://fisheye2.atlassian.com/browse/eclipselink/trunk/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/sessions/UnitOfWorkImpl.java?r=HEAD#l4171

      Thank you very much for reply
     Martin

--------------------------------------------------------------------------------------- CODE: entities
@Entity
@Table(name = "CATEGORY")
public class GeoCategory implements Serializable {

    ...

    @Id
    @GeneratedValue(strategy = GenerationType.TABLE, generator = "SEQ_CATEGORY")
    @Column(name = "ID_CATEGORY", nullable = false)
    private long idCategory;

    @ManyToOne
    @JoinColumn(name = "parent", referencedColumnName = "ID_CATEGORY")
    private GeoCategory parent;

    @OneToMany(mappedBy = "parent", cascade = {CascadeType.MERGE, CascadeType.REFRESH, CascadeType.PERSIST})
    @PrivateOwned
    private List<GeoCategory> children;

    @OneToMany(mappedBy = "category", cascade = {})
//    @OneToMany(mappedBy = "category", cascade = {CascadeType.MERGE, CascadeType.REFRESH, CascadeType.PERSIST})
//    @OneToMany(mappedBy = "category", cascade = CascadeType.ALL)
    @PrivateOwned
    private List<GeoEntity>   entities;

    ...

    public void addCategory(int index, final GeoCategory category) {
        if(category == null) throw new IllegalArgumentException("category is null");
        if(children == null) children = new ArrayList<GeoCategory>();
        if(category.getParent() != null) {
            if(equals(category.getParent())) {
                int baseIndex = children.indexOf(category);
                if(baseIndex >=0 && baseIndex < index) index--;
                children.remove(category);
            } else
                category.getParent().removeCategory(category);
        }
        if(index >= children.size())
            children.add(category);
        else
            children.add(index, category);
        category.setParent(this);
    }

    public void removeCategory(final GeoCategory category) {
        if(category == null) throw new IllegalArgumentException("category is null");
        if(children != null &&  children.remove(category)) {
            category.setParent(null);
        }
    }
}

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "TYPE", discriminatorType = DiscriminatorType.STRING, length = 2)
@Table(name = "ENTITY")
@DefTranslation
public abstract class GeoEntity implements Serializable {

    ...

    @Id
    @GeneratedValue(strategy = GenerationType.TABLE, generator = "SEQ_ENTITY")
    @Column(name = "ID_ENTITY", nullable = false)
    private long idEntity;

    @JoinColumn(name = "CATEGORY_ID", referencedColumnName = "ID_CATEGORY", nullable = false)
    @ManyToOne(optional = false)
    private GeoCategory     category;

    ...
}


--------------------------------------------------------------------------------------- CODE: init tables

    private static void init() {
        EntityManager em = null;
        try {
            em = entityManagerBegin();

            GeoCategory category = new GeoCategory();
            category.setCategoryName("Name 1");

            GeoCategory category2 = new GeoCategory();
            category2.setCategoryName("Name 2");
            category2.setParent(category);
            category.getChildren().add(category2);

            addEntities(category2, 2);

            GeoCategory category3 = new GeoCategory();
            category3.setCategoryName("Name 3");
            category3.setParent(category);
            category.getChildren().add(category3);

            addEntities(category3, 1);

            em.persist(category);
            em.persist(category2);
            em.persist(category3);

            entityManagerCommit(em);  // transaction commit
        } finally {
            entityManagerClose(em);  // rollback active transaction and close EM
        }
    }

    private static void addEntities(final GeoCategory category, final int count) {
        String prefix = category.getCategoryName() + " - entity: ";
        for(int index = 0; index < count; index++) {
            GeoEntity entity = new GeoEntity(prefix + index);
            category.addEntity(entity);
        }
    }

--------------------------------------------------------------------------------------- CODE: method move

    public void move(final GeoCategory dstCategory, final GeoCategory srcCategory, final int index) throws Exception {
        if(dstCategory == null) throw new IllegalArgumentException("dstCategory is null");
        if(srcCategory == null) throw new IllegalArgumentException("srcCategory is null");

        EntityManager em = null;
        try {
            em = entityManagerBegin();  // create EM and begin transaction
            em.setFlushMode(FlushModeType.COMMIT);

            GeoCategory dc = em.merge(dstCategory);
            GeoCategory sc = em.merge(srcCategory);
            
            dc.addCategory(index, sc);

            entityManagerCommit(em);  // transaction commit
        } finally {
            entityManagerClose(em);  // rollback active transaction and close EM
        }
    }

--------------------------------------------------------------------------------------- CODE: test
            em = emf.createEntityManager();
            GeoCategory dst = em.find(GeoCategory.class, 3L);
            GeoCategory src = em.find(GeoCategory.class, 2L);
            entityManagerClose(em);  // rollback active transaction and close EM
            em = null;

            move(dst, src, 1);

--------------------------------------------------------------------------------------- LOGGING_LEVEL: FINE

[EL Info]: 2010-10-05 09:59:46.51--ServerSession(27891041)--Thread(Thread[main,5,main])--EclipseLink, version: Eclipse Persistence Services - 2.2.0.v20101002-r8292
[EL Fine]: 2010-10-05 09:59:47.641--Thread(Thread[main,5,main])--Detected Vendor platform: org.eclipse.persistence.platform.database.JavaDBPlatform
[EL Config]: 2010-10-05 09:59:47.663--ServerSession(27891041)--Connection(17743384)--Thread(Thread[main,5,main])--connecting(DatabaseLogin(
	platform=>JavaDBPlatform
	user name=> ""
	datasource URL=> "jdbc:derby:/home/jandam/ddl/geobase;create=true"
))
[EL Config]: 2010-10-05 09:59:47.665--ServerSession(27891041)--Connection(24749215)--Thread(Thread[main,5,main])--Connected: jdbc:derby:/home/jandam/ddl/geobase
	User: APP
	Database: Apache Derby  Version: 10.5.3.0 - (802917)
	Driver: Apache Derby Embedded JDBC Driver  Version: 10.5.3.0 - (802917)
[EL Config]: 2010-10-05 09:59:47.665--ServerSession(27891041)--Connection(19333383)--Thread(Thread[main,5,main])--connecting(DatabaseLogin(
	platform=>JavaDBPlatform
	user name=> ""
	datasource URL=> "jdbc:derby:/home/jandam/ddl/geobase;create=true"
))
[EL Config]: 2010-10-05 09:59:47.666--ServerSession(27891041)--Connection(26873835)--Thread(Thread[main,5,main])--Connected: jdbc:derby:/home/jandam/ddl/geobase
	User: APP
	Database: Apache Derby  Version: 10.5.3.0 - (802917)
	Driver: Apache Derby Embedded JDBC Driver  Version: 10.5.3.0 - (802917)
[EL Info]: 2010-10-05 09:59:47.728--ServerSession(27891041)--Thread(Thread[main,5,main])--file:/home/jandam/java/projects/RadioLab App/RL GeoBase/RL GeoBase Base/classes/_rl-geobase-1-0_url=jdbc:derby:/home/jandam/ddl/geobase;create=true login successful
[EL Fine]: 2010-10-05 09:59:47.794--ServerSession(27891041)--Connection(24749215)--Thread(Thread[main,5,main])--SELECT ID_CATEGORY, CAT_NAME, CAT_NOTE, parent FROM CATEGORY WHERE (ID_CATEGORY = ?)
	bind => [3]
[EL Fine]: 2010-10-05 09:59:48.044--ServerSession(27891041)--Connection(24749215)--Thread(Thread[main,5,main])--SELECT ID_CATEGORY, CAT_NAME, CAT_NOTE, parent FROM CATEGORY WHERE (ID_CATEGORY = ?)
	bind => [1]
[EL Fine]: 2010-10-05 09:59:48.05--ServerSession(27891041)--Connection(24749215)--Thread(Thread[main,5,main])--SELECT ID_CATEGORY, CAT_NAME, CAT_NOTE, parent FROM CATEGORY WHERE (ID_CATEGORY = ?)
	bind => [2]
TEST move
[EL Fine]: 2010-10-05 09:59:48.055--ServerSession(27891041)--Connection(24749215)--Thread(Thread[main,5,main])--SELECT ID_CATEGORY, CAT_NAME, CAT_NOTE, parent FROM CATEGORY WHERE (parent = ?)
	bind => [1]
[EL Fine]: 2010-10-05 09:59:48.066--ServerSession(27891041)--Connection(24749215)--Thread(Thread[main,5,main])--SELECT ID_CATEGORY, CAT_NAME, CAT_NOTE, parent FROM CATEGORY WHERE (parent = ?)
	bind => [3]
[EL Fine]: 2010-10-05 09:59:48.071--ServerSession(27891041)--Connection(24749215)--Thread(Thread[main,5,main])--SELECT ID_CATEGORY, CAT_NAME, CAT_NOTE, parent FROM CATEGORY WHERE (parent = ?)
	bind => [2]
[EL Fine]: 2010-10-05 09:59:48.072--ServerSession(27891041)--Connection(24749215)--Thread(Thread[main,5,main])--SELECT ID_ENTITY, TYPE, ENTITY_NAME, CATEGORY_ID, ATTR_ID, DATA, LON_MIN, LAT_MIN, LON_MAX, LAT_MAX, VALUE_ASL, VALUE, LON, LAT FROM ENTITY WHERE (CATEGORY_ID = ?)
	bind => [2]
[EL Fine]: 2010-10-05 09:59:48.096--ClientSession(30476335)--Connection(26873835)--Thread(Thread[main,5,main])--UPDATE CATEGORY SET parent = ? WHERE (ID_CATEGORY = ?)
	bind => [3, 2]
[EL Fine]: 2010-10-05 09:59:48.144--ClientSession(30476335)--Connection(26873835)--Thread(Thread[main,5,main])--DELETE FROM ENTITY WHERE (ID_ENTITY = ?)
	bind => [2]
[EL Fine]: 2010-10-05 09:59:48.159--ClientSession(30476335)--Connection(26873835)--Thread(Thread[main,5,main])--DELETE FROM ENTITY WHERE (ID_ENTITY = ?)
	bind => [1]
TEST move - DONE
[EL Config]: 2010-10-05 09:59:48.163--ServerSession(27891041)--Connection(24749215)--Thread(Thread[main,5,main])--disconnect
[EL Info]: 2010-10-05 09:59:48.163--ServerSession(27891041)--Thread(Thread[main,5,main])--file:/home/jandam/java/projects/RadioLab App/RL GeoBase/RL GeoBase Base/classes/_rl-geobase-1-0_url=jdbc:derby:/home/jandam/ddl/geobase;create=true logout successful
[EL Config]: 2010-10-05 09:59:48.164--ServerSession(27891041)--Connection(17743384)--Thread(Thread[main,5,main])--disconnect
[EL Config]: 2010-10-05 09:59:48.164--ServerSession(27891041)--Connection(26873835)--Thread(Thread[main,5,main])--disconnect


Back to the top