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

ASF subversion and git services commented on OPENJPA-3019:
----------------------------------------------------------

Commit 01df365a2208e2b037472f90dfbb26c1790e6570 in openjpa's branch 
refs/heads/OPENJPA-3021 from Richard Zowalla
[ https://gitbox.apache.org/repos/asf?p=openjpa.git;h=01df365a2 ]

[OPENJPA-3019] Keep orphan removal on a relation that also cascades remove

Since OPENJPA-2940 the annotation parser applied cascade=REMOVE/ALL after
orphanRemoval, so the immediate cascade replaced the dependent marking and
an element removed from such a collection was no longer deleted. Apply
orphanRemoval last again and remove a dependent value together with its
owner, as the specification requires for orphanRemoval.


> In-place change to an element of a collection converted as a whole is not 
> written
> ---------------------------------------------------------------------------------
>
>                 Key: OPENJPA-3019
>                 URL: https://issues.apache.org/jira/browse/OPENJPA-3019
>             Project: OpenJPA
>          Issue Type: Bug
>            Reporter: Richard Zowalla
>            Assignee: Richard Zowalla
>            Priority: Major
>
> A change made in place to an element of a collection that is converted as a 
> whole is not written to the database. Given
> {code:java}
> @Convert(converter = ItemListConverter.class)   // 
> AttributeConverter<List<Item>, String>
> private List<Item> items = new ArrayList<>();
> {code}
> the following commits without an {{UPDATE}}, and the change is lost:
> {code:java}
> em.getTransaction().begin();
> em.find(InPlaceConvertedEntity.class, 
> 1L).getItems().get(0).setName("changed");
> em.getTransaction().commit();
> {code}
> Adding or removing an element is written. So is a change made in place to a 
> converted attribute that is not a collection, e.g. {{@Convert(converter = 
> ItemConverter.class) private Item item}} followed by 
> {{getItem().setName("changed")}}. Only the collection case is affected. The 
> collection is wrapped in a proxy that tracks adds and removes, and the field 
> is only marked dirty through that proxy, so a change inside an element is 
> never seen.
> The specification requires the change to be written. Section "Type Conversion 
> of Basic Attributes": "A converted attribute is considered a basic 
> attribute". Section "Synchronization to the Database": "A modification to the 
> state of an entity might include an assignment of a new value to a persistent 
> property or field of the entity, or even modification of a mutable value of a 
> persistent property or field."
> Mapping a collection converted as a whole only works with OPENJPA-3017 (PR 
> #220). Reported there by Francesco Chicchiriccò while testing Apache Syncope 
> against 4.2.0-SNAPSHOT: changing a value of a {{PlainAttr}} held in a 
> converted {{List<PlainAttr>}} and merging the user produced no {{UPDATE}}, 
> while removing the attribute, changing it and adding it back did.
> Test case, on top of OPENJPA-3017, package 
> {{org.apache.openjpa.persistence.conversion}}:
> {code:java}
> @Converter
> public class ItemConverter implements AttributeConverter<Item, String> {
>     public String convertToDatabaseColumn(Item attribute) {
>         return attribute == null ? null : attribute.getName();
>     }
>     public Item convertToEntityAttribute(String dbData) {
>         return dbData == null ? null : new Item(dbData);
>     }
> }
> @Entity
> public class InPlaceConvertedEntity {
>     @Id
>     private long id;
>     @Convert(converter = ItemListConverter.class)
>     private List<Item> items = new ArrayList<>();
>     @Convert(converter = ItemConverter.class)
>     private Item item;
>     // getters and setters
> }
> public class TestConvertedInPlaceChange extends SingleEMFTestCase {
>     public void setUp() {
>         setUp(InPlaceConvertedEntity.class, CLEAR_TABLES);
>         try (EntityManager em = emf.createEntityManager()) {
>             em.getTransaction().begin();
>             InPlaceConvertedEntity e = new InPlaceConvertedEntity();
>             e.setId(1L);
>             e.getItems().add(new Item("one"));
>             e.getItems().add(new Item("two"));
>             e.setItem(new Item("single"));
>             em.persist(e);
>             em.getTransaction().commit();
>         }
>     }
>     // fails: expected:<[changed]> but was:<[one]>
>     public void testElementOfConvertedListChangedInPlace() {
>         try (EntityManager em = emf.createEntityManager()) {
>             em.getTransaction().begin();
>             em.find(InPlaceConvertedEntity.class, 
> 1L).getItems().get(0).setName("changed");
>             em.getTransaction().commit();
>         }
>         try (EntityManager em = emf.createEntityManager()) {
>             assertEquals("changed",
>                 em.find(InPlaceConvertedEntity.class, 
> 1L).getItems().get(0).getName());
>         }
>     }
>     // passes
>     public void testConvertedValueChangedInPlace() {
>         try (EntityManager em = emf.createEntityManager()) {
>             em.getTransaction().begin();
>             em.find(InPlaceConvertedEntity.class, 
> 1L).getItem().setName("changed");
>             em.getTransaction().commit();
>         }
>         try (EntityManager em = emf.createEntityManager()) {
>             assertEquals("changed", em.find(InPlaceConvertedEntity.class, 
> 1L).getItem().getName());
>         }
>     }
>     // passes
>     public void testConvertedListChangedStructurally() {
>         try (EntityManager em = emf.createEntityManager()) {
>             em.getTransaction().begin();
>             em.find(InPlaceConvertedEntity.class, 1L).getItems().add(new 
> Item("three"));
>             em.getTransaction().commit();
>         }
>         try (EntityManager em = emf.createEntityManager()) {
>             assertEquals(3, em.find(InPlaceConvertedEntity.class, 
> 1L).getItems().size());
>         }
>     }
> }
> {code}
> {{Item}} is a plain {{Serializable}} bean with a {{name}} property, and 
> {{ItemListConverter}} joins the names with commas, as in the tests of 
> OPENJPA-3017.
> Possible fix: at flush, compare the converted database value of such a field 
> with the value it had when it was loaded, and mark the field dirty when they 
> differ. Alternatively, do not proxy a collection that is converted as a whole 
> and treat it like the non-collection case.



--
This message was sent by Atlassian Jira
(v10.3.26#10030026)

Reply via email to