On Sat, Nov 14, 2009 at 2:41 AM, Marc Logemann <[email protected]> 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 <[email protected]> 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 <[email protected]>
>>>> 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 <[email protected]>
>>>>>> Date: Fri, Nov 13, 2009 at 9:52 AM
>>>>>> Subject: Re: inverse OneToMany relation - getting weird
>>>>>> To: [email protected]
>>>>>>
>>>>>>
>>>>>> 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 <[email protected]>
>>>>>> 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
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>
>>>
>