users@glassfish.java.net

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

From: Gordon Yorke <gordon.yorke_at_oracle.com>
Date: Fri, 16 Feb 2007 16:44:05 -0500

There is still a bug here. TopLink should not be inserting new
instances. The merge will not automatically occur (the new phone will
not be inserted and the transaction could still fail with a foreign key
constraint violation) but TopLink should detect the referenced phones
and treat them like detached references as defined in the
specification. Please file a bug for the unexpected insert.
--Gordon

Markus Fuchs wrote:
> 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
>>
>>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe_at_glassfish.dev.java.net
> For additional commands, e-mail: users-help_at_glassfish.dev.java.net
>
>