Alright I will open a JIRA issue fort his.
In my test I use the javaagent, in my app I use compile-time enhancement.
Thank you for the suggestion. However in my original problem I have a list of product order
lines with @OrderColumn (transparent to the application) and orhpanRemoval = true. A UI shows
the ordered list of product lines and I am making copy/paste so the user can copy them (either
to the same or new product order) or reorder them so the order is really important. (On a
copy I make a new order line with id and version set to null).
Regards,
Henno
-----Oorspronkelijk bericht-----
Van: Rick Curtis [mailto:curtisr7@gmail.com]
Verzonden: maandag 21 februari 2011 23:22
Aan: users@openjpa.apache.org
Onderwerp: Re: adding new entities to an existing List fails when using GenerationType.IDENTITY
Henno --
Try changing :
firstSaved.getProducts().addAll(0, Arrays.asList(banana, pear));
to
firstSaved.getProducts().addAll(Arrays.asList(banana, pear));
In my tests it seemed to make the problem go away... we're somehow getting
confused when writing the join table on the second update. Please go ahead
and open a JIRA for this issue.
Thanks,
Rick
On Mon, Feb 21, 2011 at 1:47 PM, Rick Curtis <curtisr7@gmail.com> wrote:
> How are you enhancing your Entities?
>
> Thanks,
> Rick
>
>
> On Mon, Feb 21, 2011 at 11:22 AM, Henno Vermeulen <henno@huizemolenaar.nl>wrote:
>
>> Although this workaround works in my toy example, it does not seem to work
>> in our application, switching to GenerationType.TABLE does.
>>
>> Henno
>>
>> -----Oorspronkelijk bericht-----
>> Van: Henno Vermeulen [mailto:henno@huizemolenaar.nl]
>> Verzonden: maandag 21 februari 2011 17:50
>> Aan: 'users@openjpa.apache.org'
>> Onderwerp: RE: adding new entities to an existing List fails when using
>> GenerationType.IDENTITY
>>
>> I found a workaround:
>>
>> In my test I directly added the new ProductOrderLines to the List in the
>> ProductOrder. I do not know the implementation of this List because it is
>> the one returned by OpenJPA (at least after detaching).
>> When I set the list reference to a new arraylist and add both the existing
>> elements and the new ones to this list, the test passes.
>> I.e. change the line
>>
>> firstSaved.getProducts().addAll(0, Arrays.asList(banana, pear));
>>
>> to
>>
>> List<ProductOrderLine> newProducts = new
>> ArrayList<ProductOrderLine>();
>> firstSaved.getProducts().addAll(Arrays.asList(banana,
>> pear));
>> newProducts.addAll(firstSaved.getProducts());
>> firstSaved.setProducts(newProducts);
>>
>> Makes the test work.
>>
>> Regards, Henno
>>
>>
>> -----Oorspronkelijk bericht-----
>> Van: Henno Vermeulen [mailto:henno@huizemolenaar.nl]
>> Verzonden: maandag 21 februari 2011 17:19
>> Aan: 'users@openjpa.apache.org'
>> Onderwerp: adding new entities to an existing List fails when using
>> GenerationType.IDENTITY
>>
>> Hello,
>>
>> I think I found a serious issue (in both OpenJPA 2.0.0 and 2.1.0) when I
>> try to add new entities to an existing list and I use a generated identity
>> with GenerationType.IDENTITY.
>>
>> I start with a fresh database and let OpenJPA create the schema. I have a
>> ProductOrder entity that contains a List of ProductOrderLines, annotated as
>> such:
>>
>> @Entity
>> public class ProductOrder {
>> ...
>> @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
>> private List<ProductOrderLine> products = new
>> ArrayList<ProductOrderLine>();
>> ...
>> }
>>
>> The entity in the List (ProductOrderLine) has a generated id with
>> GenerationType.IDENTITY.
>>
>> @Entity
>> public class ProductOrderLine {
>>
>> @Id
>> @GeneratedValue(strategy = GenerationType.IDENTITY)
>> private Long id;
>> ...
>> }
>>
>> I start with a ProductOrder that has these products:
>> 1 - orange
>> 2 - apple
>>
>> I insert two new products into the list so that I get:
>> null - banana
>> null - pear
>> 1 - orange
>> 2 - apple
>>
>> Then I merge the entity (I work with attach/detach, not sure if this
>> matters).
>> OpenJPA merge correctly returns a ProductOrder with this list:
>>
>> 3 - banana
>> 4 - pear
>> 1 - orange
>> 2 - apple
>>
>> However OpenJPA generates the wrong SQL so that the database contains
>> something completely different and indeed selecting the ProductOrder by it's
>> id gives:
>>
>> 3 - banana
>> 4 - pear
>> 4 - pear
>> 4 - pear
>>
>> I tested this with sql server. (I tried hsqldb but this also suffers from
>> bug https://issues.apache.org/jira/browse/OPENJPA-1066).
>> This problem does not occur when I use GenerationType.AUTO for
>> ProductOrderLine. My example uses a join table, but foreign key columns seem
>> to have the same problem. Should I use another generation type? If so which
>> one, and is it compatible with existing sql server data that had id values
>> automatically generated by sql server?
>>
>> Please let me know if I should file a bug report and if I should attempt
>> to convert my unit test to one accepted by OpenJPA standards.
>>
>> Regards,
>> Henno Vermeulen
>>
>>
>> package entities;
>>
>> import javax.persistence.Entity;
>> import javax.persistence.GeneratedValue;
>> import javax.persistence.GenerationType;
>> import javax.persistence.Id;
>>
>> @Entity
>> public class ProductOrderLine {
>>
>> @Id
>> @GeneratedValue(strategy = GenerationType.IDENTITY)
>> private Long id;
>>
>> private String name;
>>
>> public ProductOrderLine() {
>> }
>>
>> public ProductOrderLine(String name) {
>> this.name = name;
>> }
>>
>> public String getName() {
>> return name;
>> }
>>
>> public void setName(String name) {
>> this.name = name;
>> }
>>
>> public Long getId() {
>> return id;
>> }
>>
>> }
>>
>>
>> package entities;
>>
>> import java.util.ArrayList;
>> import java.util.List;
>>
>> import javax.persistence.CascadeType;
>> import javax.persistence.Entity;
>> import javax.persistence.FetchType;
>> import javax.persistence.GeneratedValue;
>> import javax.persistence.GenerationType;
>> import javax.persistence.Id;
>> import javax.persistence.OneToMany;
>>
>> @Entity
>> public class ProductOrder {
>>
>> @Id
>> @GeneratedValue(strategy = GenerationType.IDENTITY)
>> private Long id;
>>
>> // Workaround for
>> https://issues.apache.org/jira/browse/OPENJPA-1947
>> private String name;
>>
>> @OneToMany(cascade = CascadeType.ALL, fetch =
>> FetchType.EAGER)
>> private List<ProductOrderLine> products = new
>> ArrayList<ProductOrderLine>();
>>
>> public ProductOrder() {
>> }
>>
>> public Long getId() {
>> return id;
>> }
>>
>> public void setProducts(List<ProductOrderLine> products) {
>> this.products = products;
>> }
>>
>> public List<ProductOrderLine> getProducts() {
>> return products;
>> }
>>
>> }
>>
>> import java.util.ArrayList;
>> import java.util.Arrays;
>> import java.util.Collections;
>> import java.util.Comparator;
>> import java.util.List;
>>
>> import javax.persistence.EntityManager;
>> import javax.persistence.EntityManagerFactory;
>> import javax.persistence.Persistence;
>>
>> import junit.framework.TestCase;
>> import entities.ProductOrder;
>> import entities.ProductOrderLine;
>>
>> /**
>> * I tested this with MSSQL SERVER (I tried hsqldb but this suffers from an
>> * additional problem where it mixes up id 0 with id null, see
>> * https://issues.apache.org/jira/browse/OPENJPA-1066)/
>> *
>> * @author Henno Vermeulen
>> */
>> public class ProductOrderTest extends TestCase {
>>
>> private EntityManagerFactory factory;
>>
>> public void setUp() {
>> factory =
>> Persistence.createEntityManagerFactory("testPU", System
>>
>> .getProperties());
>> }
>>
>> public void testProductOrderLineCopy() {
>> // If we do this, it fails after the first
>> save!!!!
>> // hsqldb seems to convert null to 0 and
>> confuse this with an existing
>> // id or something
>> // insertSomeData();
>>
>> ProductOrder original = new ProductOrder();
>> ArrayList<ProductOrderLine> products = new
>> ArrayList<ProductOrderLine>();
>> products.addAll(Arrays.asList(new
>> ProductOrderLine("orange"),
>> new
>> ProductOrderLine("apple")));
>> original.setProducts(products);
>>
>> // START
>> // null - orange
>> // null - apple
>> printProducts("Before first save:",
>> original);
>> ProductOrder firstSaved = save(original);
>> // 1 - orange
>> // 2 - apple
>> printProducts("After first save:",
>> firstSaved);
>>
>> ProductOrderLine orange =
>> firstSaved.getProducts().get(0);
>> ProductOrderLine apple =
>> firstSaved.getProducts().get(1);
>> assertEquals("orange", orange.getName());
>> assertEquals("apple", apple.getName());
>> Long orangeId = orange.getId();
>> Long appleId = apple.getId();
>> assertTrue(orangeId != null && appleId !=
>> null);
>>
>> ProductOrderLine banana = new
>> ProductOrderLine("banana");
>> ProductOrderLine pear = new
>> ProductOrderLine("pear");
>> assertTrue(banana.getId() == null &&
>> pear.getId() == null);
>>
>> firstSaved.getProducts().addAll(0,
>> Arrays.asList(banana, pear));
>> // Changed to
>> // null - banana
>> // null - pear
>> // 1 - orange
>> // 2 - apple
>> printProducts("Before second save:",
>> firstSaved);
>> assertExpectedProductLines(firstSaved,
>> orangeId, appleId, true);
>>
>> ProductOrder secondSaved = save(firstSaved);
>> // Expected after save:
>> // 3 - banana
>> // 4 - pear
>> // 1 - orange
>> // 2 - apple
>>
>> // On SQL server this is actually returned
>> by save, but not by find!
>> printProducts("After second save:",
>> secondSaved);
>> assertExpectedProductLines(secondSaved,
>> orangeId, appleId, false);
>>
>> ProductOrder found =
>> findById(secondSaved.getId());
>> printProducts("Found by id after second
>> save:", found);
>> // This one fails!!!!
>> // On SQL server this returns
>> // 3 - banana
>> // 4 - pear
>> // 4 - pear
>> // 4 - pear
>> assertExpectedProductLines(found, orangeId,
>> appleId, false);
>> }
>>
>> private void printProducts(String description, ProductOrder
>> order) {
>> System.out.println(description);
>> for (ProductOrderLine p :
>> order.getProducts()) {
>> System.out.println(p.getId()
>> + " - " + p.getName());
>> }
>> }
>>
>> private void assertExpectedProductLines(ProductOrder line,
>> Long orangeId,
>> Long appleId, boolean
>> beforeMerge) {
>> List<ProductOrderLine> products = new
>> ArrayList<ProductOrderLine>();
>> products.addAll(line.getProducts());
>> Collections.sort(products, new
>> Comparator<ProductOrderLine>() {
>> @Override
>> public int
>> compare(ProductOrderLine o1, ProductOrderLine o2) {
>> return
>> o1.getName().compareTo(o2.getName());
>> }
>> });
>> assertEquals("apple",
>> products.get(0).getName());
>> assertEquals(appleId,
>> products.get(0).getId());
>> assertEquals("banana",
>> products.get(1).getName());
>> assertEquals(beforeMerge, null ==
>> products.get(1).getId());
>> assertEquals("orange",
>> products.get(2).getName());
>> assertEquals(orangeId,
>> products.get(2).getId());
>> assertEquals("pear",
>> products.get(3).getName());
>> assertEquals(beforeMerge, null ==
>> products.get(3).getId());
>> }
>>
>> private ProductOrder save(ProductOrder order) {
>> EntityManager em =
>> factory.createEntityManager();
>> em.getTransaction().begin();
>>
>> ProductOrder result;
>> if (order.getId() == null) {
>> em.persist(order);
>> result = order;
>> } else {
>> result = em.merge(order);
>> }
>>
>> em.getTransaction().commit();
>> em.detach(result);
>> em.close();
>> return result;
>> }
>>
>> private ProductOrder findById(Long id) {
>> EntityManager em =
>> factory.createEntityManager();
>> em.getTransaction().begin();
>> ProductOrder result =
>> em.find(ProductOrder.class, id);
>> em.getTransaction().commit();
>> em.detach(result);
>> em.close();
>> return result;
>> }
>>
>> }
>>
>> <persistence xmlns="http://java.sun.com/xml/ns/persistence"
>> xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
>> xsi:schemaLocation="http://java.sun.com/xml/ns/persistencepersistence_1_0.xsd"
>> version="1.0">
>>
>> <persistence-unit name="testPU">
>>
>> <provider>org.apache.openjpa.persistence.PersistenceProviderImpl
>> </provider>
>> <class>entities.ProductOrder</class>
>> <class>entities.ProductOrderLine</class>
>>
>> <exclude-unlisted-classes>true</exclude-unlisted-classes>
>> <properties>
>> <property
>> name="openjpa.jdbc.SynchronizeMappings" value="buildSchema" />
>> <property
>> name="openjpa.ConnectionDriverName"
>>
>> value="com.microsoft.sqlserver.jdbc.SQLServerDriver" />
>> <property
>> name="openjpa.ConnectionURL"
>>
>> value="jdbc:sqlserver://localhost\\SQL2008:1433;databaseName=obliprototypeunittest"
>> />
>> <property
>> name="openjpa.ConnectionUserName" value="obliprototype" />
>> <property
>> name="openjpa.ConnectionPassword" value="hidden" />
>> <property name="openjpa.Log"
>> value="DefaultLevel=INFO" />
>> </properties>
>> </persistence-unit>
>> </persistence>
>>
>>
>
|