Problems with ManyToOne and OneToMany

View: New views
5 Messages — Rating Filter:   Alert me  

Problems with ManyToOne and OneToMany

by orgler :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi,
 
I'm using eclipselink to do some persistence. I'm having the following classes/tables:
 
@Entity
public class Team{
    @OneToMany(mappedBy="team")
    public Set<Player> players;
}

@Entity
public class Player{
    @ManyToOne
    public Team team;
}
 
In my database there is a table team and a table player (with a foreign-key-relationship to a team-ID).
 
This works as far as I'm not deleting anything. But when calling em.remove(myPlayer) the "players"-Set in "Team" is not automatically updated. When closing my application and restarting it, everything works fine. But without this restart the "players"-array seems to get cached somewhere.
 
Any idea on how to solve this? From time to time I'm getting errors that there are unpersistet instances after such a remove operation. For hibernate, I've read something about an "inverse"-annotation which could (if I understood it right) solve such a problem.
 
Any help would be highly appreciated,
 
best regards
-Johannes
 

_______________________________________________
eclipselink-users mailing list
eclipselink-users@...
https://dev.eclipse.org/mailman/listinfo/eclipselink-users

Re: Problems with ManyToOne and OneToMany

by Joe Mc. :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi,

you have to tell JPA to cascade the persistence operations on the relations.
See for example:
http://wiki.eclipse.org/Introduction_to_EclipseLink_JPA_(ELUG)#.40OneToMany

@OneToMany(mappedBy="team", cascade = {CascadeType.REMOVE})
if you want, that only remove operations will be cascaded.

I hope that helps!

McJoe



Johannes Michler-2 wrote:
Hi,

I'm using eclipselink to do some persistence. I'm having the following
classes/tables:

@Entity
public class Team{
    @OneToMany(mappedBy="team")
    public Set<Player> players;
}

@Entity
public class Player{
    @ManyToOne
    public Team team;
}

In my database there is a table team and a table player (with a
foreign-key-relationship to a team-ID).

This works as far as I'm not deleting anything. But when calling
em.remove(myPlayer) the "players"-Set in "Team" is not automatically
updated. When closing my application and restarting it, everything works
fine. But without this restart the "players"-array seems to get cached
somewhere.

Any idea on how to solve this? From time to time I'm getting errors that
there are unpersistet instances after such a remove operation. For
hibernate, I've read something about an "inverse"-annotation which could (if
I understood it right) solve such a problem.

Any help would be highly appreciated,

best regards
-Johannes

_______________________________________________
eclipselink-users mailing list
eclipselink-users@eclipse.org
https://dev.eclipse.org/mailman/listinfo/eclipselink-users

Parent Message unknown Re: Problems with ManyToOne and OneToMany

by christopher delahunt :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Some parts of this message have been removed. Learn more about Nabble's security policy.

Hello Johannes,

 

JPA does not maintain relationships for you, and instead requires applications to maintain both sides of every relationship so that they remain consistent with what is in the database.  What that means here is that when you are deleting a Player, you also need to remove any references that might remain in the object model to the deleted player - in this case remove the player from the players set.  If not, Team will reference the removed player until it gets refreshed. 

 

The application has the same issue when you add a player to a team - the application must set both sides of the relationship, or the object model may not reflect what gets set in the database. 

 

Hope this helps.

Chris


----- Original Message -----
From: "Orgler" <orgler@...>
To: "Eclipselink-Users" <eclipselink-users@...>
Sent: Sunday, July 12, 2009 7:19:39 AM GMT -05:00 US/Canada Eastern
Subject: [eclipselink-users] Problems with ManyToOne and OneToMany

Hi,
 
I'm using eclipselink to do some persistence. I'm having the following classes/tables:
 
@Entity
public class Team{
    @OneToMany(mappedBy="team")
    public Set<Player> players;
}

@Entity
public class Player{
    @ManyToOne
    public Team team;
}
 
In my database there is a table team and a table player (with a foreign-key-relationship to a team-ID).
 
This works as far as I'm not deleting anything. But when calling em.remove(myPlayer) the "players"-Set in "Team" is not automatically updated. When closing my application and restarting it, everything works fine. But without this restart the "players"-array seems to get cached somewhere.
 
Any idea on how to solve this? From time to time I'm getting errors that there are unpersistet instances after such a remove operation. For hibernate, I've read something about an "inverse"-annotation which could (if I understood it right) solve such a problem.
 
Any help would be highly appreciated,
 
best regards
-Johannes
 

_______________________________________________
eclipselink-users mailing list
eclipselink-users@...
https://dev.eclipse.org/mailman/listinfo/eclipselink-users

Re: Problems with ManyToOne and OneToMany

by orgler :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi,
@Chris: Yes this is what was my solution so far, to update the collections on add and remove manually. But this is quite ugly :-( Using @PostRemove or @PreRemove also didn't really help and caused ugly problems from time to time. For hibernate there is a special non-jpa-standard annotation (I think it could be "inverse", but I'm not quite sure and I couldn't find the site I read about this again) to handle this. If I understood you right, there is no such thing for EclipseLink :-(

@Joe: I think the Cascade.Remove doesn't really help. As mentioned, my database get's updated the right way. I couldn't see any effect on my issue when using the @cascade annotation unfortunately.

Any way, thanks for your help. I fear I'll have to do the updates of the collections manually :-(

-Johannes

2009/7/13 <christopher.delahunt@...>

Hello Johannes,

 

JPA does not maintain relationships for you, and instead requires applications to maintain both sides of every relationship so that they remain consistent with what is in the database.  What that means here is that when you are deleting a Player, you also need to remove any references that might remain in the object model to the deleted player - in this case remove the player from the players set.  If not, Team will reference the removed player until it gets refreshed. 

 

The application has the same issue when you add a player to a team - the application must set both sides of the relationship, or the object model may not reflect what gets set in the database. 

 

Hope this helps.

Chris


----- Original Message -----
From: "Orgler" <orgler@...>
To: "Eclipselink-Users" <eclipselink-users@...>
Sent: Sunday, July 12, 2009 7:19:39 AM GMT -05:00 US/Canada Eastern
Subject: [eclipselink-users] Problems with ManyToOne and OneToMany

Hi,
 
I'm using eclipselink to do some persistence. I'm having the following classes/tables:
 
@Entity
public class Team{
    @OneToMany(mappedBy="team")
    public Set<Player> players;
}

@Entity
public class Player{
    @ManyToOne
    public Team team;
}
 
In my database there is a table team and a table player (with a foreign-key-relationship to a team-ID).
 
This works as far as I'm not deleting anything. But when calling em.remove(myPlayer) the "players"-Set in "Team" is not automatically updated. When closing my application and restarting it, everything works fine. But without this restart the "players"-array seems to get cached somewhere.
 
Any idea on how to solve this? From time to time I'm getting errors that there are unpersistet instances after such a remove operation. For hibernate, I've read something about an "inverse"-annotation which could (if I understood it right) solve such a problem.
 
Any help would be highly appreciated,
 
best regards
-Johannes
 

_______________________________________________
eclipselink-users mailing list
eclipselink-users@...
https://dev.eclipse.org/mailman/listinfo/eclipselink-users



_______________________________________________
eclipselink-users mailing list
eclipselink-users@...
https://dev.eclipse.org/mailman/listinfo/eclipselink-users

Re: Problems with ManyToOne and OneToMany

by sonavor :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

This revelation has been a little disappointing.

I have also run into this problem with JPA (Eclipselink) and I am wondering about a couple of things I have seen.

Using the same scenario of a parent -> child table relationship as Mr Johannes except using Collection -

@Entity
public class Team{
     @OneToMany(mappedBy="team")
     public Collection<Player> players;

     ...getter and setters for Team attributes
 }

 @Entity
 public class Player{
     @JoinColumn(name = "team_id", referencedColumnName = "team_id")
     @ManyToOne
     public Team team;

     ...getter and setters for Player attributes
 }

I can get the Player record's foreign key: team_id to populate automatically during a create operation by doing -

... aTeam is a new instance of the Team class that has not yet been created in the database
... playerList is a collection of Player objects that have not yet been created in the datase

em.persist(aTeam);

for (Iterator it=playerList.iterator(); it.hasNext(); ) {
    Player player = (Player) it.next();
    em.persist(player);
    player.setTeam(aTeam);
}

The result of that is a new Team record in the Team table and however many Player records in the Player table with foreign key values set to the parent Team record.

However, if I change the code to be like this -

em.persist(aTeam);

for (Iterator it=playerList.iterator(); it.hasNext(); ) {
    Player player = (Player) it.next();
    em.persist(player);
    aTeam.getPlayers().add(player);
}

The new Team record gets created and so do the new Player records except none of the Player record foreign key values are set to the parent Team record.  The Player record team_id values are NULL.

Is that just a flaw with the current JPA implementation?  

I have found that Many-to-Many relationships using a mapping table don't have this problem.
For instance if the Team entity class had another reference to something like Sponsers where a Sponser could sponser many teams and teams could have many sponsers you might have this -

@Entity
public class Team{
     @OneToMany(mappedBy="team")
     public Collection<Player> players;
     
     @JoinTable(name = "TEAM_SPONSER_MAP", joinColumns = {@JoinColumn(name = "TEAM_ID",referencedColumnName = "TEAM_ID")}, inverseJoinColumns = {@JoinColumn(name = "SPONSER_ID", referencedColumnName = "SPONSER_ID")})
    @ManyToMany
    private Collection<SPONSER> sponsers;

     ...getter and setters for Team attributes
 }

 @Entity
 public class Sponser{
     @ManyToMany(mappedBy = "sponsers", fetch = FetchType.LAZY)
     public Collection<Team> teams;

     ...getter and setters for Sponser attributes
 }

 @Entity
 public class Player{
     @JoinColumn(name = "team_id", referencedColumnName = "team_id")
     @ManyToOne
     public Team team;

     ...getter and setters for Player attributes
 }

 In this case doing an operation like this -

 ....sponserList is a Collection<Sponser> that has been populated with Sponser objects to be linked to a Team object
.....aTeam is a Team entity that has just been created

 em.persist(aTeam);

 for ( Iterator it = sponserList.iterator(); it.hasNext(); ) {
      Sponser sponser = (Sponser)it.next();
      aTeam.getSponsers().add(sponser);
 }

 The result is the TEAM_SPONSER_MAP table gets automatically populated with the linked Team and Sponser records.

 One last example of a problem involving the first case of the ManyToOne mapping -
In the case of an update where a Team entity is retrieved from the database and includes a populated collection of team Players.  If an edit operation removes a player (or more than one player) from the Team object "players" collection and an entity manager is used to update the Team using a merge:

em.merge(aTeam);  ....where aTeam is the entity object the edit operation manipulated

The merge process will not handle the players collection properly and the players removed from the aTeam object do not get deleted.  The remove has to be done manually in the code without using the "merge" method.

In the case of the ManyToMany Team - Sponsers relationship however, the mapping table entries are handled nicely by a "merge" operation.

It seems to be the ManyToOne and OneToMany relationships that developers have to handle manually.
OneToOne relationships seem to work fine.

-sonavor

Johannes Michler-2 wrote:
Hi,
@Chris: Yes this is what was my solution so far, to update the collections
on add and remove manually. But this is quite ugly :-( Using @PostRemove or
@PreRemove also didn't really help and caused ugly problems from time to
time. For hibernate there is a special non-jpa-standard annotation (I think
it could be "inverse", but I'm not quite sure and I couldn't find the site I
read about this again) to handle this. If I understood you right, there is
no such thing for EclipseLink :-(

@Joe: I think the Cascade.Remove doesn't really help. As mentioned, my
database get's updated the right way. I couldn't see any effect on my issue
when using the @cascade annotation unfortunately.

Any way, thanks for your help. I fear I'll have to do the updates of the
collections manually :-(

-Johannes

2009/7/13 <christopher.delahunt@oracle.com>

> Hello Johannes,
>
>
>
> JPA does not maintain relationships for you, and instead requires
> applications to maintain both sides of every relationship so that they
> remain consistent with what is in the database.  What that means here is
> that when you are deleting a Player, you also need to remove any references
> that might remain in the object model to the deleted player - in this case
> remove the player from the players set.  If not, Team will reference the
> removed player until it gets refreshed.
>
>
>
> The application has the same issue when you add a player to a team - the
> application must set both sides of the relationship, or the object model may
> not reflect what gets set in the database.
>
>
>
> Hope this helps.
>
> Chris
>
>
> ----- Original Message -----
> From: "Orgler" <orgler@gmail.com>
> To: "Eclipselink-Users" <eclipselink-users@eclipse.org>
> Sent: Sunday, July 12, 2009 7:19:39 AM GMT -05:00 US/Canada Eastern
> Subject: [eclipselink-users] Problems with ManyToOne and OneToMany
>
> Hi,
>
> I'm using eclipselink to do some persistence. I'm having the following
> classes/tables:
>
> @Entity
> public class Team{
>     @OneToMany(mappedBy="team")
>     public Set<Player> players;
> }
>
> @Entity
> public class Player{
>     @ManyToOne
>     public Team team;
> }
>
> In my database there is a table team and a table player (with a
> foreign-key-relationship to a team-ID).
>
> This works as far as I'm not deleting anything. But when calling
> em.remove(myPlayer) the "players"-Set in "Team" is not automatically
> updated. When closing my application and restarting it, everything works
> fine. But without this restart the "players"-array seems to get cached
> somewhere.
>
> Any idea on how to solve this? From time to time I'm getting errors that
> there are unpersistet instances after such a remove operation. For
> hibernate, I've read something about an "inverse"-annotation which could (if
> I understood it right) solve such a problem.
>
> Any help would be highly appreciated,
>
> best regards
> -Johannes
>
>
> _______________________________________________
> eclipselink-users mailing list
> eclipselink-users@eclipse.org
> https://dev.eclipse.org/mailman/listinfo/eclipselink-users
>
>

_______________________________________________
eclipselink-users mailing list
eclipselink-users@eclipse.org
https://dev.eclipse.org/mailman/listinfo/eclipselink-users