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:19:06 -0400

Sorry, below I meant create a new instance of HashSet :)

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