• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Tim Cooke
  • Ron McLeod
  • paul wheaton
  • Jeanne Boyarsky
Sheriffs:
  • Paul Clapham
  • Devaka Cooray
Saloon Keepers:
  • Tim Holloway
  • Roland Mueller
  • Himai Minh
Bartenders:

Problem with One-To-Many bi-directional mapping

 
Ranch Hand
Posts: 77
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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
Posts: 77
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Nobody has any ideas?
 
john lazeraski
Ranch Hand
Posts: 77
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Still stuck on this.. hoping someone might have some thoughts.
 
Ranch Hand
Posts: 55
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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
Posts: 77
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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
Posts: 55
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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.
 
Consider Paul's rocket mass heater.
reply
    Bookmark Topic Watch Topic
  • New Topic