users@glassfish.java.net

Re: TopLink Essentials bug with Set<Something> fields?

From: Markus Fuchs <Markus.Fuchs_at_Sun.COM>
Date: Thu, 15 Feb 2007 15:37:30 -0800

Hi Witold,

Looks like the problem is that the instances in the new Set<Phone> are
detached. Try changing setPhones to

@Stateless
public class PersonService implements PersonServiceRemote {
...
public void setPhones(Long personId, Set<Phone> phones) {
     Person p = em.getReference(Person.class, personId);
     Set <Phone> mergedPhones = new Set<Phone>();

     for (Phone phone : phones) {
          Phone mergedPhone = em.merge(phone);
          mergedPhones.add(mergedPhone);
     }
     p.setPhones(mergedPhones);
 }
...
}

Also note, that JPA relationships should always be maintained on both
sides. So if above relationship is bi-directional, you'd need to compare
the original and new Set<Phone> and do the appropriate updates
(add/remove) on the Phone side manually.

-- markus.

Witold Szczerba wrote:
> Hello there,
> I have big problems with TopLink Essentials and it looks like there is
> some bug.
> Here is the case:
>
> @Entity
> public class Person extends EntityBase<Long,Long> {
> .....
> public static final String PHONES = "phones";
> @ManyToMany
> private Set<Phone> phones;
> ....
> public Set<Phone> getPhones() {
> return phones;
> }
>
> public void setPhones(Set<Phone> phones) {
> Set<Phone> old = this.phones;
> this.phones=phones;
> firePropertyChange(PHONES,old,phones);
> }
> ....
> }
> where EntityBase<K,V> is a non @Entity base class.
>
> I have Swing application using @Remote interfaces to access database:
>
> @Stateless
> public class PersonService implements PersonServiceRemote {
> ....
> public List<Phone> getPhones(Long personId) {
> Query query = em.createQuery(
> "SELECT p.phones FROM Person p WHERE p.id=?1");
> query.setParameter(1,personId);
> return query.getResultList();
> }
> ....
> public void setPhones(Long personId, Set<Phone> phones) {
> Person p = em.getReference(Person.class, personId);
> p.setPhones(phones);
> }
> ...
> }
>
> Here is what happens:
> in Swing application I call:
> Set<Phone> phones = personService.getPhones(1); //1 is Person PK
> phones collection contains one phone entity, then I call:
> personService.setPhones(phones);
>
> then TopLink is trying ONCE AGAIN to insert that phone ID and person
> ID into PERSON_PHONE table which causes exception as that row already
> exists in PERSON_PHONE table. When I call:
> personService.setPhones(new HashSet<Phone>());
> then TopLink is doing everything OK, I mean it is removing existing
> row from database.
>
> I really do not know what to do, as there is no way to force TopLink
> to add any new phone into that set. Every time when my Set contains
> something that already is in PERSON_PHONE table I get exception,
> because it is trying to add existing phones again.
>
> I was trying that in Glassfish v1 with TopLink from that release and I
> have also replaced libraries with TopLink Essentials Version 2 Build
> 25 (but still on Glassfish V1).
> Is that a bug?
>
> p.s.
> I suppose the problem might have been not discovered as, in my case,
> TopLink's Set implementation is serialized and deserialized back and
> fourth between server and Swing application. Maybe no one made a test
> case for that?
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe_at_glassfish.dev.java.net
> For additional commands, e-mail: users-help_at_glassfish.dev.java.net
>