openjpa-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Michael Dick <michael.d.d...@gmail.com>
Subject Re: inverse OneToMany relation - getting weird
Date Sat, 14 Nov 2009 21:45:01 GMT
On Sat, Nov 14, 2009 at 2:41 AM, Marc Logemann <li@logemann.org> wrote:

> Hi,
>
> thanks for your infos on that. I will stick with setting the backrefs
> manually as you did it and keep chosing the @ManyToOne on the child. What
> strikes me even more is that you can just do that:
>
> public class Team {
>
>    ...
>
>    @OneToMany(cascade = CascadeType.PERSIST, mappedBy = "team")
>    public List<Player> players;
> }
>
> public class Player {
>
>    ....
>
>    @ManyToOne
>    public Team team;
>
> }
>
>
> So no ElementJoinColumn or JoinColumn as i would need to if using
> unidirectional links from parent to child. Makes kind of sense because now
> mapping the parent in the child class, i dont need to tell him where the FK
> thingy is. Now its just a direct mapping and the defaults are ok to map to
> the FK field "team_oid" in the Player Table.
>
> To me the documentation is lacking heavily in exactly this spot. Because it
> turns out that the bidirectional mapping of a child-FK-Mapping is completely
> different as the unidirectional one because then we would need all that
> ElementJoinColumn magic. Took me one day to figure this out and you helped
> me in getting the facts straight that the ORM layer is not that smart as i
> believed. For me, OpenJPA could easily figure the backrefs for itself, at
> least it looks as it could do so.
>

OpenJPA can - with the InverseManager option. I don't use it often though so
I sometimes forget about it, and there might be some bugs or "unexpected
behavior" when using it.


> Would be interessting to know if this keeps being this way in Version 2.
> But on the other hand, it wont kill you to set the backref, you just have to
> know it in the first place. And now i finally created test classes for all
> that mapping stuff so that i can fiddle around with various mappings in a
> short timeframe w/o boostrapping my J2EE app.
>

It isn't changed in the JPA 2.0 spec (which is nearly finalized). We could
change the default for OpenJPA though (basically turn on InverseManager
automatically). I'd have to think about that a bit (it makes me nervous
messing with the contents of a user's POJO without explicitly being told to
do so).

What do other people think?

-mike

Again, thanks a lot for your help.
>
>
> ---
> regards
> Marc Logemann
> http://www.logemann.org
> http://www.logentis.de
>
>
>
>
> Am 13.11.2009 um 19:09 schrieb Michael Dick:
>
>
>  Hi Marc,
>>
>> The example I sent was something I hacked together to populate a database
>> using your model. Basically it creates 3 Fathers with 2 children for each
>> of
>> them. Hopefully that didn't distract you too much.
>>
>> The real issue is setting the backrefs. In JPA the application must
>> maintain
>> both sides of a bi-directional relationship (on your Java objects).
>> There's
>> some wording in the spec to this effect which I can drag up if you're
>> interested.
>>
>> The other thing that might be worth noting is that when you add
>> mappedBy="something" JPA will consider the Many side (in your case Child,
>> or
>> Player) the _owner_ of the relationship. Using the @Embedded annotations
>> may
>> reverse the owners - but you need to remove the mappedBy attribute of
>> @OneToMany. It's the owner of the relationship which matters "most".
>>
>> So for general JPA use I definitely recommend setting both sides of the
>> relationship to make sure they get persisted properly.
>>
>> That said, OpenJPA does provide a mechanism to manage the inverse side of
>> relationships for you. You can read about it in the users guide here :
>>
>> http://openjpa.apache.org/builds/1.2.1/apache-openjpa-1.2.1/docs/manual/manual.html#ref_guide_inverses
>> .
>> It sounds like it's exactly what you're looking for.
>>
>> Hope this helps.  If you have other questions keep posting.
>>
>> -mike
>>
>> On Fri, Nov 13, 2009 at 11:39 AM, Marc Logemann <li@logemann.org> wrote:
>>
>>  Hi,
>>>
>>> for the records, i am using 1.2.0.
>>>
>>> To your question: i am only doing that (sorry, i changed my example to be
>>> Team->Player, instead of Father->Child) :
>>>
>>>      Player p = new Player();
>>>      p.setName("Huiboo");
>>>      List<Player> list = new ArrayList<Player>();
>>>      list.add(p);
>>>
>>>      Team t = new Team();
>>>      t.setName("VfL");
>>>      t.setPlayers(list);
>>>      em.persist(t);
>>>
>>> So yes, i am only setting the child references in the list and i dont
>>> manually set the backreference. To be honest,  i dont understand your
>>> example too well. I wouldnt expect that i need to do the backreferences
>>> manually.
>>>
>>> At this point i know something that works without setting backrefs
>>> manually, but this looks also quite weird to me because i must use
>>> OneToOne
>>> on the child. If i do the mapping on the Team (Father) like this:
>>>
>>>  @OneToMany(cascade = CascadeType.PERSIST)
>>>  @ElementJoinColumn(name = "team_oid", referencedColumnName = "oid")
>>>  public List<Player> players;
>>>
>>> and then do the mappedBy in the child (player)
>>>
>>>  @OneToOne(mappedBy = "players")
>>>  public Team team;
>>>
>>> Then i have my bidirectional link and i also have the FK column filled
>>> like
>>> if i wouldnt use the mappedBy.
>>>
>>> Would you recommend doing it like you have done it? As i said, i would
>>> expect the ORM layer to work out the back reference because i already
>>> defined the relationship via setting childs to a list, why telling the
>>> childs again to which object they belong?
>>>
>>> Thanks for being with me on that one. Appreciate that.
>>>
>>>
>>>
>>> ---
>>> regards
>>> Marc Logemann
>>> http://www.logemann.org
>>> http://www.logentis.de
>>>
>>>
>>>
>>>
>>> Am 13.11.2009 um 18:27 schrieb Michael Dick:
>>>
>>>
>>> Hi Marc,
>>>
>>>>
>>>> Are you setting the relationship for both the Father and Child entities?
>>>>
>>>> I see the behavior you describe if I do this :
>>>>     Father f;
>>>>     Child c;
>>>>     for (int i = 0; i < nFathers; i++) {
>>>>         f = new Father();
>>>>         f.setChildren(new ArrayList<Child>());
>>>>         em.persist(f);
>>>>
>>>>         for(int j = 0 ; j < nChildren; j++ ) {
>>>>             c = new Child();
>>>> //                c.setFather(f);
>>>>             f.getChildren().add(c);
>>>>             em.persist(c);
>>>>         }
>>>>
>>>>
>>>> Uncommenting c.setFather(f); fixes the problem. If that doesn't help let
>>>> me
>>>> know which version of OpenJPA and which database you're using and I'll
>>>> try
>>>> to recreate.
>>>>
>>>> -mike
>>>>
>>>> On Fri, Nov 13, 2009 at 10:33 AM, Marc Logemann <li@logemann.org>
>>>> wrote:
>>>>
>>>> Hi,
>>>>
>>>>>
>>>>> what you have done works of course but thats not my problem because
>>>>> thats
>>>>> what i had before i wanted to do the inverse. Your example simply
>>>>> demonstrates how to use ElementJoinColumn and i am pretty aware of that
>>>>> ;-)
>>>>> The problem starts when using mappedBy on the children inside Father.
>>>>>
>>>>> When i am doing it as you described it in your email before, i am at
>>>>> least
>>>>> not getting any errors back but instead he inserts a "null" in my FK
>>>>> field.
>>>>>
>>>>> @ManyToOne
>>>>> @ForeignKey
>>>>> @JoinColumn(name="team_oid", referencedColumnName="oid")
>>>>> public Team team;
>>>>>
>>>>> I am really clueless. It simply cant be so hard and uncommon to make
an
>>>>> inverse OneToMany with a FK field in the child table.
>>>>>
>>>>> I googled for hours and all example i ve found just dont work.
>>>>>
>>>>>
>>>>>
>>>>> ---
>>>>> regards
>>>>> Marc Logemann
>>>>> http://www.logemann.org
>>>>> http://www.logentis.de
>>>>>
>>>>>
>>>>>
>>>>>
>>>>> Am 13.11.2009 um 17:17 schrieb Michael Dick:
>>>>>
>>>>>
>>>>> Hi Marc,
>>>>>
>>>>>
>>>>>> Did some more reading and I was wrong about the use case for the
>>>>>> @Element
>>>>>> annotations. The @Element annotations allow you to specify the FK
>>>>>> constraint
>>>>>> on the One side of a @OneToMany, so your annotations would look like
>>>>>> this
>>>>>> :
>>>>>>
>>>>>> @Entity
>>>>>> public class Father extends Person {
>>>>>> @OneToMany
>>>>>> @ElementForeignKey
>>>>>> @ElementJoinColumn(name="father_oid", referencedColumnName="oid")
>>>>>> Collection<Child> children;
>>>>>> . . .
>>>>>> }
>>>>>>
>>>>>> @Entity
>>>>>> public class Child extends Person {
>>>>>> @ManyToOne
>>>>>> private Father father;
>>>>>> . . .
>>>>>> }
>>>>>>
>>>>>> It appears to be functionally identical to using @JoinColumn and
>>>>>> @ForeignKey
>>>>>> on the Child class, but the documentation is a bit sparse on this
>>>>>> annotation..
>>>>>>
>>>>>> There are several examples in our unit tests though. For example
>>>>>>
>>>>>>
>>>>>>
>>>>>> openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/mapping/bidi/ParentWithAutoIdentity.java
>>>>>> looks somewhat similar to your model.
>>>>>>
>>>>>> Hope this helps,
>>>>>> -mike
>>>>>>
>>>>>>
>>>>>> ---------- Forwarded message ----------
>>>>>> From: Michael Dick <michael.d.dick@gmail.com>
>>>>>> Date: Fri, Nov 13, 2009 at 9:52 AM
>>>>>> Subject: Re: inverse OneToMany relation - getting weird
>>>>>> To: users@openjpa.apache.org
>>>>>>
>>>>>>
>>>>>> Hi Marc,
>>>>>>
>>>>>> I think the @ElementForeignKey and @ElementJoinColumn annotations
are
>>>>>> intended to be used with non-entity types (ie PersistentCollections).
>>>>>>
>>>>>> If Child is an entity you'd want to use @ForeignKey and @JoinColumn
>>>>>> instead
>>>>>> (I gave this a quick try and it looks like it worked for me).
>>>>>>
>>>>>> Regards,
>>>>>> -mike
>>>>>>
>>>>>>
>>>>>> On Fri, Nov 13, 2009 at 7:03 AM, Marc Logemann <li@logemann.org>
>>>>>> wrote:
>>>>>>
>>>>>> Hi,
>>>>>>
>>>>>>
>>>>>>> after struggling for several hours, i need to ask for help.
>>>>>>>
>>>>>>> Following scenario.....
>>>>>>>
>>>>>>> DB Table: Father
>>>>>>> ---------------------------
>>>>>>> INT oid
>>>>>>> ....
>>>>>>>
>>>>>>>
>>>>>>> DB Table: Childs
>>>>>>> ------------------------
>>>>>>> INT oid
>>>>>>> INT father_oid
>>>>>>> ...
>>>>>>>
>>>>>>> Java Entity: Father
>>>>>>> --------------------------
>>>>>>> ...
>>>>>>> @OneToMany(cascade = CascadeType.PERSIST, mappedBy = "father")
>>>>>>> private List<Child> childList;
>>>>>>>
>>>>>>> Java Entity: Child
>>>>>>> --------------------------
>>>>>>> ...
>>>>>>> @ManyToOne(cascade = CascadeType.PERSIST)
>>>>>>> @ElementForeignKey
>>>>>>> @ElementJoinColumn(name="father_oid", referencedColumnName="oid")
>>>>>>> protected Father father;
>>>>>>>
>>>>>>>
>>>>>>> When i try to persist a Father, i am getting:
>>>>>>>
>>>>>>> <openjpa-1.2.0-r422266:683325 fatal user error>
>>>>>>> org.apache.openjpa.persistence.ArgumentException: Field
>>>>>>> "Father.childList"
>>>>>>> declares "Child.father" as its mapped-by field, but this field
is not
>>>>>>> a
>>>>>>> direct relation. at......
>>>>>>>
>>>>>>> Ok, then i changed Child to:
>>>>>>>
>>>>>>> Java Entity: Child
>>>>>>> --------------------------
>>>>>>> ...
>>>>>>> @ManyToOne(cascade = CascadeType.PERSIST)
>>>>>>> @Column(name = "father_oid")
>>>>>>> protected Father father;
>>>>>>>
>>>>>>>
>>>>>>> When i now do persist a Father object, both DB records (Father
and
>>>>>>> Childs)
>>>>>>> are filled with records but the FK column in Child (father_oid)
is
>>>>>>> empty.
>>>>>>> So
>>>>>>> the FK relation is broken but it did persist childs, which is
somehow
>>>>>>> weird.
>>>>>>>
>>>>>>> So whatever i do, i never get a fully persisted graph with correct
FK
>>>>>>> values.
>>>>>>>
>>>>>>> Can anyone give me a hint what i am doing wrong here?
>>>>>>>
>>>>>>>
>>>>>>> Thanks a lot.
>>>>>>>
>>>>>>> ---
>>>>>>> regards
>>>>>>> Marc Logemann
>>>>>>> http://www.logemann.org
>>>>>>> http://www.logentis.de
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>
>>>
>

Mime
  • Unnamed multipart/alternative (inline, None, 0 bytes)
View raw message