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 16:09:11 -0800

Hi Witek,

Witold Szczerba wrote:
> Hi Markus,
> thanks for help, I will try that tomorrow morning :)
> Is that actually a workaround or this is how one should alter
> collection based properties in JPA?
This is not a workaround. JPA instances become detached when send across
the wire. But another possible solution for your problem would be to
modify the person instance (the phones fields) directly on the remote
side. Then in the SessionBean, call em.merge(p) and specify that the
merge operation should be cascaded in the POJO, i.e.

public class Person extends EntityBase<Long,Long> {
.....
  @ManyToMany(cascade=CascadeType.MERGE)
  private Set<Phone> phones;
....
> Are you positive that merging
> operation should not be performed by TopLink itself?
>
The merge operation must be called by the application (here:
SessionBean). For more information about the merge operation, see JPA
Spec, 3.2.4.1 Merging Detached Entity State.

Regards,

-- markus.
> Thanks again,
> Witek,
> p.s.
> This is uni-directional relationship, Phone class does not know
> anything about Person, Phone instances are supposed to be used in
> other entities as well.
>
>
> 2007/2/16, Markus Fuchs <Markus.Fuchs_at_sun.com>:
>> 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
>> >
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: users-unsubscribe_at_glassfish.dev.java.net
>> For additional commands, e-mail: users-help_at_glassfish.dev.java.net
>>
>>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe_at_glassfish.dev.java.net
> For additional commands, e-mail: users-help_at_glassfish.dev.java.net
>