• Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

What's the point of the collections on the @OneToMany side

 
Mike Cheung
Ranch Hand
Posts: 113
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi, if we create the following two entity classes, with each Employee having a collection of multiple Phones.
Can anyone explain what's the point of having the EMPLOYEE class to have a collection of PHONE objects?
In the database, no matter whether we are creating a bi-directional or uni-directional ManyToOne relationship, only the Many side (ie Phone object) contains a foreign key (ie EMPLOYEEID) column. The One side (ie Employee object) doesn't have any columns that stores the collection of Phones (ie EMPLOYEE.PHONEID). So what's the point of having this additional collection in EMPLOYEE class for a bi-directional case over a uni-directional relationship?




 
Dave Tolls
Ranch Hand
Posts: 2112
16
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Because, for example, when you are displaying the Employee you may well want to display the things it has a relationship with. In this case the list of phone numbers that Employee has.
It makes for cleaner code than getting the Employee and then getting the list of associated phones.
Obviously if that is not a requirement then don't bother with the List of phones.
 
Mike Cheung
Ranch Hand
Posts: 113
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi thanks but once persisted isn't this relationship gone when querying the Employee object? I can only go from Phone to find its owner via the FK in Phone's table when queried.

I suppose I can add a JoinTable annotation to make this truely bidirectional but this isn't generated by JPA automatically when selecting bidirectional over unidirectional. So yeah what really are we supposed to do with a Collection field that will not be persisted?
 
Dave Tolls
Ranch Hand
Posts: 2112
16
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
The collection is persisted.
Via the other side of the relationship (ie the reference in Phone to the Employee it is associated with).

The @OneToMany annotation simply tells Hibernate where to look to get the list of things.
Think of it as an additional query done after the Employee object has been retrieved from the table:
Get the Employee.
When the Phones are needed then get the Phones for that Employee.
 
Mike Cheung
Ranch Hand
Posts: 113
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Dave Tolls wrote:The collection is persisted.
Via the other side of the relationship (ie the reference in Phone to the Employee it is associated with).

Um... okay when I persist a Phone object, it automatically persists the Employee object as well (I have set cascade option as follow). At the same time, it sets the value on the FK column to reference the Employee object.


Let's have a look at some examples ...

Persist Many side (ie PHONE object)


In this case, simply setting the relationship with the following code, JPA automatically updates the FK column on the Phone table to point to the primary key of a row on the Employee table.




Persist One side (ie EMPLOYEE object)


In this case, unless I add the following block to manage the relationship manually from the other side (Many again), JPA will not set the FK column on the Phone table to point to the primary key of a row on the Employee table.


In other words, the following line is pretty much useless. So why is this done for most if not all the tutorials I see online?


The question is if this is really required or am I missing something here that could have taken care of the relationship for me?
 
Dave Tolls
Ranch Hand
Posts: 2112
16
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I've got in front of me at the moment code that has a Job which has a load of Records.
The Records are parsed from a CSV and added to a pre-existing Job, but not persisted until all rows have been handled.
Then the Job (not the individual Records) is persisted.

The relevant attribute on the Job is marked as:

Once a Record is parsed then the existing Job is set and it's added to the Job:


That seems to handle everything I need on my side.
 
Mike Cheung
Ranch Hand
Posts: 113
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Okay so you have similar annotations defined in the entity class. The following bit must be something you added in addition to the setters and getters generated automatically.


So you are handling the relationship from both ends also.
Your job.addRecord(rec); is similar to my emp.getPHONEID().add(ph);
Your rec.setJob(job); is similar to my ph.setEMPLOYEEID(emp);

In other words, I guess we have verified in both my and your case the following:
1) If persisting an object on the Many side (ie Phone for me and Record for you), we don't need to add any special functions. The generated setter is able to handle it.
2) If persisting an object on the One side (ie Employee for me and Job for you), we need to add a special function (ie addRecord in your case) on top of the generated getters and setters. This special function needs to manage relationships from both ends.
3) The Collection isn't persisted into the database. In your case, you will have a FK on the Records table pointing to a row on the Job table. But I don't believe you have any FKs on the Job table pointing to any rows on your Records table. This means the job.addRecord(rec); line can be commented out and you'll have the same result in the database.

Can you confirm by in fact commenting out the following line and see if you have the same result in your database as if it's not commented out?
job.addRecord(rec);
 
Dave Tolls
Ranch Hand
Posts: 2112
16
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Mike Cheung wrote:Okay so you have similar annotations defined in the entity class. The following bit must be something you added in addition to the setters and getters generated automatically.


So you are handling the relationship from both ends also.
Your job.addRecord(rec); is similar to my emp.getPHONEID().add(ph);
Your rec.setJob(job); is similar to my ph.setEMPLOYEEID(emp);

In other words, I guess we have verified in both my and your case the following:
1) If persisting an object on the Many side (ie Phone for me and Record for you), we don't need to add any special functions. The generated setter is able to handle it.

Pretty much.
But your existing One-side onject will not have the new Many-side object in its collection until you refresh it.
Mike Cheung wrote:
2) If persisting an object on the One side (ie Employee for me and Job for you), we need to add a special function (ie addRecord in your case) on top of the generated getters and setters. This special function needs to manage relationships from both ends.

Yep. But if the CASCADE is assigned to the One-side you get the advantage of persisting the whole thing in one go.
This may or may not be an advantage in your particular case.
As with most things codey there isn't a one-size-fits-all.
Mike Cheung wrote:
3) The Collection isn't persisted into the database. In your case, you will have a FK on the Records table pointing to a row on the Job table. But I don't believe you have any FKs on the Job table pointing to any rows on your Records table. This means the job.addRecord(rec); line can be commented out and you'll have the same result in the database.

That's the difference between relational and object. In my mind on the One-side the Collection is a representation of the relationship given by the FK on the other table. So the Collection is persisted in the only way it can be.
Mike Cheung wrote:
Can you confirm by in fact commenting out the following line and see if you have the same result in your database as if it's not commented out?
job.addRecord(rec);

It won't persist the Records because I call persist (well, merge I think) on the Job.
Since the Job does not have the Records in its List<> then the Records will not be persisted as Hibernate knows nothing about them.
No point me commenting out the code.
 
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic