Hibernate: How do I join a table with itself? - java

I have a problem joining a table. Actually I'm really lost on how to do it. I have this Hibernate table mapping.
<class name="Technology" table="TECHNOLOGIES">
<id name="technoId">
<column name="techno_id" />
<generator class="identity" />
</id>
<property name="description" type="java.lang.String">
<column name="description" />
</property>
<many-to-one name="parent" class="Technology" />
</class>
The column parent is related with the same table. An example of the table so you can understand me.
techno_id | description | parent
1------------"Java"----------null
2------------"Hibernate"------1
3------------"HQL"------------2
4------------".NET"----------null
5------------"NHibernate"----4
That's basically an example of the table, it doesn't have real data, it's just an example.
What I want to do is, in a method that receives a techno_id, run with Criteria or HQL, and that brings me a List of results with the children id's too.
For example, if I send to the method the "1" techno_id, it should bring me a List with the ids "1, 2, 3".
I hope I was as clear as possible and you can help me.
Thanks, and sorry for my english jaja.

You need to use join tag with inverse
<join table ="Technologies" inverse ="true" optional = "false">
<key column = "techno_id"/>
<many-to-one name="parent" class="Technology" />
</join>

There are two ways of doing it.
By Criteria :
1. For specific level fetching : e.g 3 level fetching(As per your example)
public Technology getAllChildrenTechnology(long parentID){
Crtieria criteria = session.createCriteria(Technology.class);
criteria.add(Restriction.eq("id",parentID));
criteria.setFetchMode("parent",FetchMode.JOIN);
criteria.setFetchMode("parent.parent",FetchMode.JOIN);
criteria.setResultTransformer(criteria.DISTINCT_ROOT_PROPERTY);
Technology techno = (Technology)criteria.uniqueResult();
return techno;
}
2. For N level Fetching : You need to create n level for loop.(Recursive loop using above).
By Lazy :
There is a feature in hibernate that allow us to fetch some joins without using criteria.
<many-to-one name="parent" class="Technology" lazy="false"/>

I believe this question is not really Hibernate specific. Even you are writing SQL, you have no easy way to get a node with all its descendant, without special handling in design.
Easiest way is to have each Technology contains List of child technologies (Bidirectional relationship). Then traverse Technology's children recursively.
If you need quick retrieval from persistence storage, you have to cater that in your design. One way is as described in an answer I wrote before for a similar question. https://stackoverflow.com/a/7524077/395202
This method is not that Hibernate friendly anyway (It still works, just need extra attentions)

Related

How to create an index in Liquibase with a column from other table?

I want to create an index for an specific sql call in which I join two tables and I don't know how to insert the outer column.
This is what I currently have:
<changeSet id="1234" author="name" >
<createIndex catalogName="catalog"
indexName="idx-master"
tableName="table-a">
<column name="type"/>
<column name="id"/>
<column name="date"/>
</createIndex>
</changeSet>
What I'm looking for is something like a tag column in which I can pass the name of the outer column, so it could be like:
<changeSet id="1234" author="name" >
<createIndex catalogName="catalog"
indexName="idx-master"
tableName="table-a">
<column name="type"/>
<column name="id"/>
<column name="date"/>
<column name="date-from-table-b">
</createIndex>
</changeSet>
Thanks
Note that an index over different tables is likely a database system specific functionality (I'm not aware of an RDBMS that supports this, but some may). Therefore a) it's unlikely that liquibase supports it with general functionality and b) if you add a custom SQL statement to create that index, your liquibase specification won't be database system independent anymore.
The latter may not be one of the reasons you use liquibase, but I'd still give a redesign of the table structure a thought. This indicates a design issue. Sometimes it's worthwhile to create a separate table for such special lookups or to store the data joined in general.
The closest you would get with general functionality is to create your index as you already wrote it down in the question and have an additional one-column index on the date in your joined table.
I don't think it's possible with special liqubiase tags, but you can always use <sql> tag and create it in plain SQL.
As such:
<changeSet id="foo" author="bar">
<sql>
CREATE INDEX some_index ON ...
</sql>
</changeSet>

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.

Java Hibernate Lazy=false

When setting Lazy=false, then hibernate will automatically loads the objects into the required sets e.g.
<set name="Options" table="ATTRIBUTEOPTION" inverse="false" cascade="all" lazy="false">
<key>
<column name="ATTRIBUTEID" />
</key>
<one-to-many class="com.BiddingSystem.Models.AttributeOption" />
</set>
but if in my xml mapping, I place lazy=true and in some place in my application i decide that i want to load all attribute options, should i do it manually, or is there a technique which lets tells hibernate that now i want to set lazy=false??
You can't change the configuration at runtime. But you can use Hiberante.initialize(..) to initialize lazy collections.
Yo can do it manually simply using getOptions(). But if when loading the entity you already now that you will need the options then you can do an eager fetch using fetch join this way:
select c from EntityX c left join fetch c.Options
And it's an important optimitzation beacuse you can avoid a lot of extra selects if you prefetch data that you will know that will be needed.

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.

Lazy One-to-One using Proxy not working

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

Categories

Resources