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:20:49 +0100

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