aspose file tools*
The moose likes EJB and other Java EE Technologies and the fly likes Problem with One-To-Many bi-directional mapping Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Java » EJB and other Java EE Technologies
Bookmark "Problem with One-To-Many bi-directional mapping" Watch "Problem with One-To-Many bi-directional mapping" New topic
Author

Problem with One-To-Many bi-directional mapping

john lazeraski
Ranch Hand

Joined: Nov 14, 2011
Posts: 76
Hi all,

I am not sure what is going on yet, I have a OneToMany on one side, and a ManyToOne on the other. One problem might be I have Cascade set to REFRESH on both sides. When I try to persist the OneToMany object, the container just hangs. I've set the one-side object on the many side object, and persist the many side object (one at a time), then try adding it to the one-side. What confuses me about the bi-directional setup.. well a few things confuse me.. first when to know if I should use bi-directional or not.. in this case, the many-side.. only gets accessed by the one-side when requested (thus its lazy fetch.. which I think is default for one-to-many anyway). I have something like (leaving a bit out for brevity):



So I know I can persist a user with no transactions added..that works fine. But when I go to persist a transaction for the user, I am not clear on if I need to simply get the user and add the transaction to the collection in the user, and that will do all the magic.. or if I need to set the user on the transaction, add the transaction to the user collection, then persist the transaction? What confuses me and I can't seem to find any info that provides a bit more detail other than a simple example... I know that if the user is managed, and I have say a property String phone.. if I call user.setPhone(), it gets stored to the DB eventually (unless I flush() which makes it immediate). But, if I have a transaction, and add it to the collection, it does NOT persist the transaction, right? I have to persist (or merge) the transaction by itself, setting the user on the transaction? Do I need to add the transaction to the user collection of transactions too? Or does the container/spec handle the magic when I persist the transaction? I am confused on this because the owning table is the transaction table. If I set the user on the transaction and persist the transaction.. the transaction_user column should contain the reference back to the user. The user entity has no column.. so I would assume I simply need to persist the transaction (with the user set on it) and that is it. If that is the case, then there is no need to set the transaction into the user collection too right?

The other thing I can't seem to figure out is the @JoinColumn. It says from the ejb book I have that you can't use it on both sides of the relationship... makes sense. But in my case, the transaction is only referenced by two entities.. the user entity, and another transaction_item entity (which is a one-to-many transaction to transaction-item). We need to refer back to the owning user for each transaction in our code.. thus I believe it should be a bidirectional relationship. If however we did not need to refer back to the user, would the @JoinColumn be on the @OneToMany user entity side, and thus there would be no getUser() ManyToOne in the transaction entity class?

Thank you all. Hoping to figure out this dang crashing issue.


john lazeraski
Ranch Hand

Joined: Nov 14, 2011
Posts: 76
Nobody has any ideas?
john lazeraski
Ranch Hand

Joined: Nov 14, 2011
Posts: 76
Still stuck on this.. hoping someone might have some thoughts.
Andrew Moko
Ranch Hand

Joined: Dec 16, 2011
Posts: 55
You dont need to have @ManyToOne & @JoinColumn declared on the TransactionEntity. Well, you can have @Column with the declared/ mapped name i.e 'user' on the getUser().

The OneToMany relationship defined in UserEntity is enough to persist a collection of incoming transactions. You just need to add the collection of transactions(into the user entity) and persist the user entity object.

However, i prefer not having OneToMany relationships defined on my entities. I simply create a field with related entity id (in this case transaction id), and manually add it. This avoids redundant entries.

I hope you know what i mean!
john lazeraski
Ranch Hand

Joined: Nov 14, 2011
Posts: 76
Hi there,

Thanks for the reply. I am not entirely sure what you mean, but I think I do. I have always figured keeping a Collection<Long> of ids and in my named queries using those ids instead of allowing the @OneToMany to handle when to load deep data would be better. Honestly, while I love the ease of the entity beans, I sort of miss using JDBC. I know we still can, but I am trying to utilize the EJB 3 capabilities, especially having read that many containers may implement caching and other performance tricks behind the scenes that avoid me having to come up with all that.

What is most difficult is remembering to set both sides of the relationship. For example, in the TransactionEntity, I want to be able to call getUser() to get the user that the transaction belongs to. As well, I want to be able to get all the transactions for one user, so the UserEntity getTransactions() should handle that. However, when storing a bunch of transactions.. what I am not sure of is.. do I persist each transaction, then add it to the collection on the user entity.. or can I do something like:



In other words, is it enough to simply get the UserEntity (managed object), grab the collection object of transactions, and add more to it, and that updates the new transactions (along with what was already there)? Or would I then need to call ue.setTransactions(trans); to cause the container to merge/persist the updated collection?

I thought I would have to do something like:



This example I would assume persists each transtion entity so thats its got a created generated ID.. setting the user on it for each. Then, updates the user side by adding all the trans to the UserEntity, then merges that object?

All gets confusing dealing with two sides. I just want to make sure user.getTransactions() returns the list of all, and transaction.getUser() refers to the owner user.

Thanks
.
Andrew Moko
Ranch Hand

Joined: Dec 16, 2011
Posts: 55
These are my thoughts..

UserEntity ue = em.find(UserEntity.class, id);
Collection<TransactionEntity> trans = ue.getTransactions();
trans.addAll(newTransactions);
em.merge(ue);

To fetch the UserEntity,
TransactionEntity te = em.find(TransactionEntity.class, id);
UserEntity ue = te.getUser();

The entity beans create all relevant associations.
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: Problem with One-To-Many bi-directional mapping