persistence@glassfish.java.net

Re: Many-To-Many on JavaSE Collection returning null

From: David Harrigan <dharrigan_at_gmail.com>
Date: Wed, 4 Apr 2007 14:29:19 +0100

Hi,

Thanks very much for the clarification and help, I appreciate it :-)

-=david=-

On 4/4/07, Tom Ware <tom.ware_at_oracle.com> wrote:
> Hi David,
>
> In JPA, retreiving an object from the cache will retrieve the actual
> instance that was added. Your call to children.clear() was clearing the
> instance of the collection that was stored in your parent object. When
> you callled find, your initial instance of parent was being retreived
> (with the clear collection)
>
> I'm glad you've got it working,
> Tom
>
> David Harrigan wrote:
>
> >Hi,
> >
> >Bingo!
> >
> >children = new HashSet<Item>();
> >
> >and my test passes. So, what do you think is happening? That certainly
> >is a gotcha for me! :-)
> >
> >Thanks.
> >
> >-=david=-
> >
> >On 4/4/07, Tom Ware <tom.ware_at_oracle.com> wrote:
> >
> >
> >>I appologize if you've already tried this.
> >>
> >>What if you remove the call to children.clear() and instead create a new
> >>instance of HashMap for your comparison.
> >>
> >>FYI: Yes, there is caching in TopLink essentials. Your call to find
> >>will create a ReadObjectQuery that queries based on the primary key.
> >>The first thing that query will do is check the cache for an item with
> >>that primary key. If you want to force the query to go to the DB, try
> >>doing an em.clear() after your initial commit().
> >>
> >>-Tom
> >>
> >>David Harrigan wrote:
> >>
> >>
> >>
> >>>Hi Tom, thanks for replying (you're probably v.busy :-) )
> >>>
> >>>Doesn't work. Here's the code:
> >>>
> >>> Item parent = itemFactory.getItem("Parent");
> >>> Item child1 = itemFactory.getItem("Child 1");
> >>> Item child2 = itemFactory.getItem("Child 2");
> >>> Item child3 = itemFactory.getItem("Child 3");
> >>> final Set<Item> children = new HashSet<Item>();
> >>> final Set<Item> child1Items = new HashSet<Item>();
> >>> final Set<Item> child2Items = new HashSet<Item>();
> >>> final Set<Item> child3Items = new HashSet<Item>();
> >>> children.add(child1);
> >>> children.add(child2);
> >>> children.add(child3);
> >>> child1Items.add(parent);
> >>> child2Items.add(parent);
> >>> child3Items.add(parent);
> >>> parent.setRelatedItems(children);
> >>> child1.setItems(child1Items);
> >>> child2.setItems(child2Items);
> >>> child3.setItems(child3Items);
> >>> em.getTransaction().begin();
> >>> em.persist(parent);
> >>> em.getTransaction().commit();
> >>> assertEquals("Should not be '0'", true, parent.getItemId() != 0);
> >>> assertEquals("Should not be '0'", true, child1.getItemId() != 0);
> >>> assertEquals("Should not be '0'", true, child2.getItemId() != 0);
> >>> assertEquals("Should not be '0'", true, child3.getItemId() != 0);
> >>>
> >>> // set all to null
> >>>
> >>> final int parentItemId = parent.getItemId();
> >>>
> >>> parent = null;
> >>> child1 = null;
> >>> child2 = null;
> >>> child3 = null;
> >>> children.clear();
> >>>
> >>> parent = em.find(Item.class, parentItemId)
> >>>
> >>> children.addAll(parent.getRelatedItems());
> >>>
> >>> assertEquals("Size should be 3", 3, children.size());
> >>>
> >>>It fails on the assert size == 3. Returns 0.
> >>>
> >>>I assume now that I'm wiring up both parts? The database looks the
> >>>same as before. Interestingly enough (but maybe just a red-herring) is
> >>>that I've set the logging to FINEST, yet I'm getting no SQL back, just
> >>>these lines (note the last line, it's doing a ReadQueryObject - does
> >>>this suggest some type of caching??? - it's not going off to the db??)
> >>>
> >>>[TopLink Fine]: 2007.04.04
> >>>12:57:20.459--ClientSession(19167401)--Connection(31742556)--Thread(Thread[main,5,main])--INSERT
> >>>INTO ITEM (ITEMID, MODIFIEDTIME, EXPIRYTIME, ITEMTYPE, RELEASETIME,
> >>>DESCRIPTION, SOURCEFILENAME, COPYRIGHT, LOCATIONURI, AGECODE,
> >>>SERVICEID, AUTHOR, CREATEDTIME, THIRDPARTYID, TITLE, TAGS_TAGSID,
> >>>PROVIDER_PROVIDERID, RESTRICTION_RESTRICTIONID) VALUES (?, ?, ?, ?, ?,
> >>>?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
> >>> bind => [4, 2007-04-04 12:57:20.396, 2007-04-04 12:57:20.396, 0,
> >>>2007-04-04 12:57:20.396, A descriptive entry, me.mpg, (C) Copyright
> >>>2007, http://www.java.net, 18, 1, David Harrigan, 2007-04-04
> >>>12:57:20.396, BBC01, Parent, 5, 7, 7]
> >>>[TopLink Finest]: 2007.04.04
> >>>12:57:20.460--UnitOfWork(7544464)--Thread(Thread[main,5,main])--Execute
> >>>query DataModifyQuery()
> >>>[TopLink Fine]: 2007.04.04
> >>>12:57:20.460--ClientSession(19167401)--Connection(31742556)--Thread(Thread[main,5,main])--INSERT
> >>>INTO ITEMRELATEDITEM (relatedItems_ITEMID, items_ITEMID) VALUES (?, ?)
> >>> bind => [5, 4]
> >>>[TopLink Finest]: 2007.04.04
> >>>12:57:20.465--UnitOfWork(7544464)--Thread(Thread[main,5,main])--Execute
> >>>query DataModifyQuery()
> >>>[TopLink Fine]: 2007.04.04
> >>>12:57:20.466--ClientSession(19167401)--Connection(31742556)--Thread(Thread[main,5,main])--INSERT
> >>>INTO ITEMRELATEDITEM (relatedItems_ITEMID, items_ITEMID) VALUES (?, ?)
> >>> bind => [6, 4]
> >>>[TopLink Finest]: 2007.04.04
> >>>12:57:20.466--UnitOfWork(7544464)--Thread(Thread[main,5,main])--Execute
> >>>query DataModifyQuery()
> >>>[TopLink Fine]: 2007.04.04
> >>>12:57:20.467--ClientSession(19167401)--Connection(31742556)--Thread(Thread[main,5,main])--INSERT
> >>>INTO ITEMRELATEDITEM (relatedItems_ITEMID, items_ITEMID) VALUES (?, ?)
> >>> bind => [7, 4]
> >>>[TopLink Finer]: 2007.04.04
> >>>12:57:20.467--ClientSession(19167401)--Connection(31742556)--Thread(Thread[main,5,main])--commit
> >>>transaction
> >>>[TopLink Finer]: 2007.04.04
> >>>12:57:20.469--UnitOfWork(7544464)--Thread(Thread[main,5,main])--end
> >>>unit of work commit
> >>>[TopLink Finer]: 2007.04.04
> >>>12:57:20.470--UnitOfWork(7544464)--Thread(Thread[main,5,main])--resume
> >>>unit of work
> >>>[TopLink Finest]: 2007.04.04
> >>>12:57:20.471--UnitOfWork(7544464)--Thread(Thread[main,5,main])--Execute
> >>>query ReadObjectQuery(orange.media.service.model.Item
> >>>
> >>>-=david=-
> >>>
> >>>
> >>>
> >>>On 4/4/07, Tom Ware <tom.ware_at_oracle.com> wrote:
> >>>
> >>>
> >>>
> >>>
> >>>>Hi David,
> >>>>
> >>>> What happens if you change your code to do the following:
> >>>>
> >>>>Item parent = new Item();
> >>>>Item child = new Item();
> >>>>Item child2 = new Item();
> >>>>
> >>>>children.add(child);
> >>>>children.add(child2);
> >>>>
> >>>>child1Items.add(parent);
> >>>>child2Items.add(parent);
> >>>>
> >>>>parent.setRelatedItems(children);
> >>>>child1.setItems(child1Items);
> >>>>child2.setItems(child2Items);
> >>>>
> >>>>em.getTransaction().begin();
> >>>>em.persist(item);
> >>>>em.getTransaction().commit();
> >>>>
> >>>> The JPA specification dictates that you have to maintain both sides of bidirectional relationahips yourself.
> >>>>
> >>>>-Tom
> >>>>
> >>>>
> >>>>
> >>>>David Harrigan wrote:
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>>Hi,
> >>>>>
> >>>>>Java 6 (update 1).
> >>>>>Glassfish v2 build = tracking cvs.
> >>>>>
> >>>>>Background:
> >>>>>
> >>>>>One class, doing a self-referential many-to-many (code has been cropped):
> >>>>>
> >>>>>@Entity
> >>>>>public Class Item {
> >>>>>
> >>>>> @Id
> >>>>> private int itemId;
> >>>>>
> >>>>> @ManyToMany(cascade = {PERSIST, MERGE, REFRESH})
> >>>>> @JoinTable("ITEMRELATEDITEM")
> >>>>> private Set<Item> relatedItems;
> >>>>>
> >>>>> @ManyToMany(mappedBy = "relatedItem")
> >>>>> private Set<Item> items;
> >>>>>
> >>>>>}
> >>>>>
> >>>>>If I then do:
> >>>>>
> >>>>>Item parent = new Item();
> >>>>>Item child = new Item();
> >>>>>Item child2 = new Item();
> >>>>>
> >>>>>children.add(child);
> >>>>>children.add(child2);
> >>>>>
> >>>>>parent.setRelatedItems(children);
> >>>>>
> >>>>>em.getTransaction().begin();
> >>>>>em.persist(item);
> >>>>>em.getTransaction().commit();
> >>>>>
> >>>>>All 3 entities get inserted into the database (assume ids, parent = 1,
> >>>>>child = 2 and child = 3)
> >>>>>
> >>>>>In the ITEMRELATEDITEM table, these rows exist:
> >>>>>
> >>>>>RELATEDITEMS_ITEMID ITEMS_ITEMID
> >>>>>2 1
> >>>>>3 1
> >>>>>
> >>>>>Okay, subsequentially, if I now do the following:
> >>>>>
> >>>>>parent = null;
> >>>>>child = null;
> >>>>>child2 = null;
> >>>>>
> >>>>>parent = em.find(Item.class, 1);
> >>>>>
> >>>>>I get back the Parent Item object, but, if I then do:
> >>>>>
> >>>>>parent.getRelatedItems()
> >>>>>
> >>>>>this returns an empty set - always.
> >>>>>
> >>>>>Even if I put FetchType.EAGER on the two annotated fields.
> >>>>>
> >>>>>If I try this within a container (GF, current cvs), it works, in that
> >>>>>getRelatedItems returns back a set with 2 items in it.
> >>>>>
> >>>>>Is there a problem with this in JavaSE?
> >>>>>
> >>>>>
> >>>>>-=david=-
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>
> >>>
> >>>
> >>>
> >
> >
> >
> >
>


-- 
PGP Key Id: E2BE72FC
Public Key: http://www.harrigan.info/public.asc