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 Tue, 22 Feb 2011 15:02:11 GMT
Henno -

I'll reformat your test case, but first can I have you re-upload your test
case and make sure to allow " Grant license to ASF for inclusion in ASF
works (as per the Apache
License<http://www.apache.org/licenses/LICENSE-2.0>ยง5)  ?
Also, please remove the @Author tag from ProductOrderTest.

Thanks,
Rick

On Tue, Feb 22, 2011 at 2:55 AM, Henno Vermeulen <henno@huizemolenaar.nl>wrote:

> I created https://issues.apache.org/jira/browse/OPENJPA-1949
>
> I attached my testcase, however it does not yet extend from
> SingleEMFTestCase because it feels a bit daunting to get started with that
> (and I have other work todo).
>
> Regards,
> Henno
>
> -----Oorspronkelijk bericht-----
> Van: Henno Vermeulen [mailto:henno@huizemolenaar.nl]
> Verzonden: dinsdag 22 februari 2011 9:32
> Aan: 'users@openjpa.apache.org'
> Onderwerp: RE: adding new entities to an existing List fails when using
> GenerationType.IDENTITY
>
> 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>
> >>
> >>
> >
>
>

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