I have a ManytoMany relationship between A and B, where A is the owning side.
I define the ManyToMany in class A:
@ManyToMany(....)
private Set<B> bs
But I don’t want to expose set in B, so no @ManyToMany attribute defined in B (e.g Set as).
It stems a problem when I want to select all B entity which an A instance is mapped to using JPA QL. I can not do:
"SELECT b FROM B b JOIN b.as A WHERE A.id = :id"
I could have set fetch = Fetch.EAGER in the @ManyToMany properties and use A.getBs() to get related B. But I prefer not to use Fetch.EAGER.
Any suggestion?
Thanks
(I had to correct myself, because it seems omitting
Set<A> asfromBaltogether won’t raise an exception.)If you only want to hide the
Set<A> asinB, then you can declare it asprivateand use a bi-directional mapping (using themappedByproperty on the non-owning side of the relation). In this case the following query runs successfully:(The example snippets are all based on the tables, data and entities found in the lower sections of the answer.)
It prints:
This JPQL query is the mapping of the following native SQL query:
You basically want a uni-directional relation (by omitting the
mappedByfromB—down below—or dropppingSet<A> as). This way, however, you won’t be able to execute a query like you’ve described. Just no way it’ll work.The persistence provider will bark at you if there is no
Set<A> asinB(property could not be resolved—in case of Hibernate). If you only omit themappedByfrom the non-owning side, then the persistence provider won’t know where is the other side of that relation. Either you use themappedByor create an inverse@JoinTableannotation inBtoo (mappedByis there so that you don’t have to the latter).If you only have a uni-directional mapping from
AtowardsByou can only fetch an A entity by its id and find all B entities that are associated with it, like this (just what you’ve described):This works for me without specifying
fetch = Fetch.EAGERand prints the same stuff as before.Beware that if
Fetch.LAZYis in effect you’ll receive errors if you try accessing lazily loaded entities after closing anEntityManageror (Hibernate)Session. You can’t do anything about this: this is the way it’s supposed to work.You can do two things to prevent BOOM from happening.
EntityManagerorSessionafter you’re done with yourAobjects and don’t use them anymore. If you callb.asbeforeemgets closed Hibernate (or any other persistence provider) will loadAobjects lazily from the database.Bentity’s@ManyToManyannotation changefetchtoFetchType.EAGER. This way, when you fetchBobjects from the database theirSet<A> asproperty will be loaded by Hiberate too (further control can be practiced with differentCascadeTypesettings—I think).I propose that you use a bi-directional mapping instead (don’t omit
mappedBy) or makeBthe owning side (but the former would be much useful).Tables
test.a
test.b
test.a_has_b
Data
test.a
test.b
test.a_has_b
Entities
A
B