| Summary: | @PrivateOwned @OneToMany elements - not undeleted in UOW in hierarchy tree (-> lose data) | ||
|---|---|---|---|
| Product: | z_Archived | Reporter: | Martin JANDA <jandam> |
| Component: | Eclipselink | Assignee: | Nobody - feel free to take it <nobody> |
| Status: | CLOSED INVALID | QA Contact: | |
| Severity: | critical | ||
| Priority: | P3 | CC: | tom.ware |
| Version: | unspecified | ||
| Target Milestone: | --- | ||
| Hardware: | PC | ||
| OS: | All | ||
| Whiteboard: | |||
@PrivateOwned object cannot be moved (by definition). They are privately owned by their owner. The only way I can imagine this working (with private owned enabled) is in separate transactions. Setting this to invalid on the basis of the commens above. The Eclipselink project has moved to Github: https://github.com/eclipse-ee4j/eclipselink |
Build Identifier: 2.1.1 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 Reproducible: Always