My question might look silly. I am new to JPA and trying to understand the underlying concepts of it. I found out that there is a #Many-to-one entity relationship that can be used there. My question is why someone would want to use this while have #One-to-many relationship?
I mean, having the latter one is enough to know the relationship and sending queries right?
if not please explain. Maybe the idea that I have about these two relationships are completely wrong. Please provide a scenario as an example so I understand better.
Thanks
OneToMany is used to map collections. If you want this relation to be bidirectional then you need to add a ManyToOne mapping on the other side.
With Hibernate mapping : Person N <---> 1 Address
<class name="Person">
<id name="id" column="personId"/>
<many-to-one name="address" column="addressId"/>
</class>
<class name="Address">
<id name="id" column="addressId"/>
<set name="people">
<key column="addressId"/>
<one-to-many class="Person"/>
</set>
</class>
ManyToOne can also be used to map a dependency between 2 objects. In this case if you want the relation to be bidirectional then you need to add a OneToOne mapping on the other side.
With Hibernate mapping : Person 1 <---> 1 Address
<class name="Person">
<id name="id" column="personId"/>
<many-to-one name="address" column="addressId" unique="true"/>
</class>
<class name="Address">
<id name="id" column="addressId"/>
<one-to-one name="person" property-ref="address"/>
</class>
#ManyToOne and #OneToManyare both part of the same concept used to describe the two sides of a single bidirectional relationship.
If you want the relationship to be unidirectional - i.e. one of the entities cannot traverse to the other, you can use one of the annotations. To decide which one, you will have to decide which entity should know about the relation and which should not.
But often you want a bidirectional relation - then you use both.
Related
This question already has answers here:
Hibernate - why use many-to-one to represent a one-to-one?
(5 answers)
Closed 7 years ago.
Reading some hibernate documentation, I've stumbled upon this pattern :
<class name="Person">
<id name="id" column="personId">
<generator class="native"/>
</id>
<many-to-one name="address"
column="addressId"
unique="true"
not-null="true"/>
</class>
<class name="Address">
<id name="id" column="addressId">
<generator class="native"/>
</id>
<one-to-one name="person"
property-ref="address"/>
</class>
from jboss hibernate doc
At first glance this seems pretty straightforward. Each Person have one and only one address, and each Address have a person.
But in a DB this pattern would allow an Address to have multiple Person referencing it, how hibernate could resolve this mapping without a list ?
How a one-to-one can have a property-ref on a many-to-one field ? I think it should only be possible to have many-to-one <=> one-to-many or one-to-one <=> one-to-one.
edit : Althought it seems possible (if not semantically correct) to make a one-to-one <=> one-to-many mapping, my question is about many-to-one <=> one-to-one.
I know that there are already some answers about one-to-one vs many-to-one on this site, but I didn't found an answer to my question in these posts.
Thank you for your time.
If you have the unique constraint in the DB, then it would not be possible that two persons have the same address.
However, if the constraint is missing and there really are multiple persons with the same address, then this mapping is not correct and you may get an exception or wrong/unpredictable results when accessing the person association in the Address entity.
I have a main table that is D1 which has a unique id of d1Id. d1Id uniquely identifies the D1 records and is also a primary key on the table. I have table 2 which is D2 which has a d2seq as a primary key but D2 also has d1Id which is unique which has a foreign key constraint (I think) on D1. But I know for sure it's unique and the id's are the same. I am trying to retrieve d2 values when i make the D1 call using hibernate and i'm unable to get the right hbm for it as i'm getting compile time errors.
The bottom line of the issue is, I need to establish a one to one relationship between 2 tables where in the second table, the id which joins is not the primary key of the table. All the examples i've seen searching google have the case where the ID on the second table is also the primary key of the second table. Let me show you the HBM file I have right now.
<hibernate-mapping default-lazy="true"
package="com.xxx.xx.customer.dto">
<class name="D1" table="D1" dynamic-update="true">
<id name="dString" column="DID" type="java.lang.String"
unsaved-value="null" length="9">
<generator class="assigned"/>
</id>
...
<one-to-one name="d2" class="com.xxx.xx.customer.dto.D2" >
<!-- column name="d1Id" /-->
</one-to-one>
In my second hbm for D2, i'm stuck here
<hibernate-mapping default-lazy="true" package="com.xxx.xx.customer.dto">
<class name="D2" table="D2" dynamic-update="true">
<id name="id" column="D2ID" type="integer">
<generator class="native">
<param name="sequence">D2SEQ</param>
</generator>
</id>
<id name="d1id" column="D1ID" type="java.lang.String"
unsaved-value="null" length="9">
<generator class="assigned"/>
</id>
I obviously can't use the second id field for d1id here because 1> it's not a primary key and 2> i've already used it before. So how should my HBM files be for this operation?
Also once I have my HBMs in place, I would like to get D2 information while i query D1 through the DTOs. How can I do that?
Why can't you use #ManyToOne relationship? Often it provides more flexibility than #OneToOne
The problem looks like this:
A Product table. 3 joined-subclasses: DVD, CD, Book.
A Role table (composite id: NAME, ROLE, PRODUCT), and subclasses by discriminator column ROLE: actor, director, artist, author, etc.. which are mapped to Actor, Director, Artist, Author java classes; (pretty usual I guess) ...
A Book has authors, a CD artists, a DVD actors and directors - these are all modelled via set with a one-to-many relation pointing to the class of the items, e.g. Author, Director, Artist, etc.. which are just subclasses of Role (see 2.)
As long as a joined-subclass has only one such set (of people/roles), all works fine. But when it has two, like DVD, actors and directors, Hibernate throws a WrongClassException?
XML excerpt (Product.hbm.xml):
<joined-subclass name="media.DVD" table="V_DVD" lazy="false">
<key column="IDPRODUCT"/>
<property column="FORMAT" name="format" type="string"/>
...
<set name="actors" lazy="false">
<key column="IDPRODUCT"/>
<one-to-many class="media.DVD$Actor"/>
</set>
<set name="directors" lazy="false">
<key column="IDPRODUCT"/>
<one-to-many class="media.DVD$Director"/>
</set>
...
</joined-subclass>
XML (Person.hbm.xml):
<class name="media.Person" table="V_ROLE">
<composite-id>
<key-property column="NAME" name="name" type="string"/>
<key-property column="ROLE" name="role" type="string"/>
<key-many-to-one class="media.Product" column="IDPRODUCT"
name="product"/>
</composite-id>
<discriminator column="ROLE" insert="false" type="string"/>
<property name="name"/>
<property name="role"/>
<many-to-one class="media.Product" column="IDPRODUCT"
insert="false" name="product" update="false"/>
<subclass discriminator-value="author" name="media.Book$Author"/>
<subclass discriminator-value="artist" name="media.Music$Artist"/>
<subclass discriminator-value="creator" name="media.DVD$Creator"/>
<subclass discriminator-value="director" name="media.DVD$Director"/>
<subclass discriminator-value="actor" name="media.DVD$Actor"/>
</class>
It seems somewhat ok to me, yet it throws an exception.
Thank you for any idea!
I've got to say, this is a rather esoteric mapping. Why are you using a composite key (with discriminator being a part of it no less) instead of surrogate?
One possible issue here is you may be manually setting discriminator value (via role property) to something other than what it should be for given subclass. Hibernate won't be able to overwrite it (discriminator is mapped with insert="false") and this would cause a WrongClassException on subsequent select.
It's also possible that there' something funky going on in the Product mapping from which media.DVD extends and which you didn't include. Can you add that as well as provide full stack trace?
The problem is basically that your model is not normalized: You tell hibernate that there is a composite key, but you use only part of that key to reference the table.
I think you can implement this by either having a set of people in your product and each person has a role, or by mapping each set to a separate (linking) table with your person table.
Another more esoteric approach would be to map to a MultiMap: In fact you have a Map<Role, Set<Person>> in your product. Hibernate does not support this out of the box, but I once wrote a UserType for this.
Cheers,
-Maarten
Good day,
I have a hibernate mapping which goes something like this
<class name="Person">
<id name="id" type="long" column="person_id" unsaved-value="null">
<generator class="sequence">
<param name="sequence">person_id_seq</param>
</generator>
</id>
...
<set name="thinCollection" table="(select person_id, person_property from some_other_table where another_property = 'something')" fetch="subselect" lazy="false">
<key column="person_id"/>
<element column="person_property" type="long"/>
</set>
...
</class>
Now my problem is, when a Person object gets flushed, it tries to execute a Collection Remove Action against Person#thinCollection, which fails because it's trying to execute delete from (select person_id, person_property from some_other_table where another_property = 'something').
Thus in line with that, how do I stop Hibernate from executing such actions (as well as update and inserts) ?
Thanks
I believe you want to use a subselect for your query, thus rendering it readonly.
http://docs.jboss.org/hibernate/stable/core/reference/en/html/mapping.html
Wouldn't
cascade="none"
Do the trick ?
[EDIT] Oups, thought it was NHibernate :P Well, I hope it would still work :)
What I currently did to solve this is to create my own persister (which is a subclass of BasicCollectionPersister) which never does an insertion/update/deletion.
But I am not sure if this is the best way to go about this or if could simply just add a magic mapping attribute to prevent the insertion/update/deletion.
[EDIT]
I found it hard to map my Set to a subselect so I used my own custom BasicCollectionPersister instead. I overriden #isRowDeleteEnabled() and #isRowInsertEnabled() to both always return false. And I overriden #doUpdateRows(..) to always return 0.
I've got a one-to-one relation between a dealer and a seller which should be lazy using a proxy. For the side on which the foreign key is defined (the seller, references the dealer), this works fine. But it doesn't work from the other side - the seller is always loaded eagerly. I set constrained="true" as described in "Some explanations on lazy loading", but that didn't help.
Following is the used mapping:
<class name="Role" table="PER_PERSROLE" abstract="true">
<id column="OID" type="long">
<generator class="native" />
</id>
<discriminator column="SUBTYPE" type="string" />
</class>
<subclass name="Dealer" extends="Role" discriminator-value="DEAL">
<property name="gpNr" column="GP_NR" type="string" />
<one-to-one name="seller" property-ref="dealer" lazy="proxy" constrained="true"
outer-join="false" />
</subclass>
<subclass name="Seller" extends="Role" discriminator-value="SELL">
<many-to-one name="dealer" column="SELLER_DEALEROID" lazy="proxy"
outer-join="false" />
</subclass>
Is it a problem that both classes reside in one table? I see that strictly speaking the relation isn't constrained on the database (it can't using this model), but the domain model always needs both entities and the application ensures this.
I think that the page you linked to explained it best, though I am not sure why it recommends setting constrained="true". If you think about it on the database level, Hibernate can't tell if the given property (the Dealer's seller) should be null or not without hitting the database (it needs to do a SELECT ... WHERE OID=:sellerOrDealerId to see if any rows are returned). And while it's hitting the database, it might as well fetch the rest of the row. From the other side of the association (Seller's dealer), there are no such problems since it has already fetched the row (and thus the SELLER_DEALEROID column).
I did encounter something similar to this once and was able to solve it by making the association non-optional (err, non-nullable)
I'm guessing you are loading session.get(id)? Have you tried load the instance using an HQL query? That will allow you to specify in the query which relationships to eager or lazy load.
HTH