openjpa-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Rick Curtis <curti...@gmail.com>
Subject Re: adding new entities to an existing List fails when using GenerationType.IDENTITY
Date Mon, 21 Feb 2011 22:21:32 GMT
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>
>>
>>
>

Mime
  • Unnamed multipart/alternative (inline, None, 0 bytes)
View raw message