Mapping Map<String,Foo> in Hibernate - java

I'm trying to map my Hashmap in Hibernate.
All examples I can find are simply like this:
class FooBar{
Map<String,String> myStrings;
}
Which would simply map to
<map role="ages">
<key column="id"/>
<index column="name" type="string"/>
<element column="age" type="string"/>
</map>
However, I use a more object-oriented approach in my Java code. Kind of like the following:
class Bar{
private Map<String, Foo> myFoos;
}
How would I go about mapping this? As the relationshop?
Of otherwise defined: How can I map a one-to-many in a Map?
Thanks,
Bart

There are a few examples in the Hibernate reference manual chapter on Collection Mapping. You would want to do something like
<map name="foos">
<key column="id"/>
<index column="name" type="string"/>
<one-to-many class="Foo"/>
</map>
The difference is <one-to-many class="Foo"/> - this will map the relationship by using a foreign key column to the ID of the Foo table in the parent table (i.e. the object that has the Map of foos).
There are several more flavors and variations of how you can map this based on exactly the type of relationship you want, see the manual for more examples.

Related

Why using a #Many-to-one in JPA entity relationships?

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.

How to map 2 identical tables in Hibernate hbm file?

I have tables like Trade_PAC_UNADJUSTED and Trade_PAC_ADJUSTED. Similary for other regions .The table structure is same and they all belong to the same schema. How do i map these tables. I don't want to duplicate the properties of the class entries in .hbm file. Also my POJO class will be same for all of them.
Please help.
Is it possible to have something like this :
<class name="com.Bean" table="TRADE" entity-name="TRADE">
<discriminator type="string">
<column name="PROCESSING_LOCATION" />
</discriminator>
<property name="..........></property>
<subclass name ="com.Bean" discriminator-value="PAC">
<discriminator type="integer">
<column name="RUN_ID" />
</discriminator>
<subclass name ="com.Bean" discriminator-value="1" entity-name="TRADE_PAC_UADJUSTED"/>
<subclass name ="com.Bean" discriminator-value="2,3,4,5,6,7,8,9" entity-name="TRADE_PAC_ADJUSTED"/>
</subclass>
</class>
But there is no way i can pass the table name within subclass ?
If you create a new POJO object and ask Hibernate to save it, how will it know which of your tables it should insert into? You will need something in your POJO to tell it which way to go.
You might be able to do this using a Hibernate "discriminator" to treat this as an inheritance scenario.

How to split a table's data into two sets based on a column value with Hibnernate mappings?

Suppose there are three tables:
Table A (ID, NAME)
Table B (ID, NAME)
Table A-B (A_ID, B_ID, Boolean_Property)
and Table A and B are modeled by classes A and B as follows:
public class A {
private long id;
private String name;
// All the B's that belong to A where the boolean property is True
Set<B> trueBSet;
// All the B's that belong to A where the boolean property is False
Set<B> falseBSet;
}
public class B {
private long id;
private String name;
}
How would I model this using Hibernate? I would like to be able to do the following, but it appears that discriminator column values don't exist for set attributes:
<class name="A" table="A">
<id name="id" column="ID">
<generator class="native" />
</id>
<property name="name" column="NAME" />
<set name="trueB" table="A-B">
<key column="A_ID"/>
<many-to-many column="B_ID" class="B"/>
<discriminator column="Boolean_Property" value="True" />
</set>
<set name="falseB" table="A-B">
<key column="A_ID"/>
<many-to-many column="B_ID" class="B"/>
<discriminator column="Boolean_Property" value="False" />
</set>
</class>
I think, you can apply where clause in set tag. Hibernate document state as follows in following link
http://docs.jboss.org/hibernate/core/3.3/reference/en/html/collections.html
where (optional): specifies an arbitrary SQL WHERE condition that is used when retrieving or removing the collection. This is useful if the collection needs to contain only a subset of the available data.
as #ChssPly76 said this is a duplicate of
Multiple #ManyToMany sets from one join table
The solutions there suggest to use a view as Join-Column and plain SQL for CRUD operations.
This Answer is marked community wiki so if anyone else wants this question to leave the 'unanswered' section may freely upvote it.

Hibernate WrongClassException / Sets / Discriminators?

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

Hibernate set mapped to a 'sql select' table

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.

Categories

Resources