persistence@glassfish.java.net

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

From: Tom Ware <tom.ware_at_oracle.com>
Date: Wed, 04 Apr 2007 09:14:00 -0400

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=-
>>>
>>>
>>>
>>>
>>>
>>>
>
>
>
>