openjpa-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Marc Logemann ...@logemann.org>
Subject Re: inverse OneToMany relation - getting weird
Date Sat, 14 Nov 2009 08:41:09 GMT
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.

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.

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
View raw message