Hibernate mapping with multiple but separate Primary Keys (OR) - java

I am currently working with hibernate and have already tried for a couple of weeks to find a solution for the following problem. As always a change of the tables is not possible.
There are two tables like this:
Table 1
-> ID
-> REF_ID
-
Table 2
-> ID
ID is the primary key for each table. REF_ID is mostly 0, but sometimes contains valid IDs.
So I am looking to realize something like that in hibernate:
select
....
from
Table1 this_
inner join
Table2 this_1_
on this_.ID=this_1_.ID
or this_.REF_ID=this_1_.ID
I have to apply certain criterias in the java code so I probably cannot use HQL. Also I am already using the code for other tables, so ideally I would like to use mapping files. My current mapping files look like this:
<hibernate-mapping>
<class name="Table1" table="Table1">
<id name="ID" type="string">
<column name="ID" />
</id>
<join table = "Table2" fetch = "join">
<key column ="ID"/>
</join>
</class>
</hibernate-mapping>
I hope someone can suggest a good approach.

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>

Hibernate set index on multiple columns while one of the columns is the ID

Is it possible to set index of multiple columns while the one of columns is the Primary Key
See this post (googled java hibernate jpa index):
JPA: defining an index column
Specifying an Index (Non-Unique Key) Using JPA
http://www.objectdb.com/java/jpa/entity/index
Then see that (googled java hibernate jpa index composite):
How to define index by several columns in hibernate entity?
You can do it like this:
<id name="id" type="NumericInteger">
<column name="ID" index="INDEX01"/>
</id>
The key is to remove column="ID" as property of Node <id> and place it as <column> definition instead

hibernate one to one on foreign key

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

Hibernate: How do I join a table with itself?

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)

Mapping two tables 0..n in Hibernate

I have a table Users
CREATE TABLE "USERS" (
"ID" NUMBER NOT NULL ,
"LOGINNAME" VARCHAR2 (150) NOT NULL )
and I have a second table SpecialUsers. No UserId can occur twice in the SpecialUsers table, and only a small subset of the ids of users in the Users table are contained in the SpecialUsers table.
CREATE TABLE "SPECIALUSERS" (
"USERID" NUMBER NOT NULL,
CONSTRAINT "PK_SPECIALUSERS" PRIMARY KEY ("USERID") )
ALTER TABLE "SPECIALUSERS" ADD CONSTRAINT "FK_SPECIALUSERS_USERID" FOREIGN KEY ("USERID")
REFERENCES "USERS" ("ID")
/
Mapping the Users table in Hibernate works ok
<hibernate-mapping package="com.initech.domain">
<class name="com.initech.User" table="USERS">
<id name="id" column="ID" type="java.lang.Long">
<meta attribute="use-in-tostring">true</meta>
<generator class="sequence">
<param name="sequence">SEQ_USERS_ID</param>
</generator>
</id>
<property name="loginName" column="LOGINNAME" type="java.lang.String" not-null="true">
<meta attribute="use-in-tostring">true</meta>
</property>
</class>
</hibernate-mapping>
But I'm struggling in creating the mapping for the SpecialUsers table. All the examples (e.g. in Hibernate documentation) in Internet I found don't have this type of self-reference. I tried a mapping like this:
<hibernate-mapping package="com.initech.domain">
<class name="com.initech.User" table="SPECIALUSERS">
<id name="id" column="USERID">
<meta attribute="use-in-tostring">true</meta>
<generator class="foreign">
<param name="property">user</param>
</generator>
</id>
<one-to-one name="user" class="User"/>
</class>
</hibernate-mapping>
but got the error
Invocation of init method failed; nested exception is org.hibernate.DuplicateMappingException:
Duplicate class/entity mapping com.initech.User
How should I map the SpecialUsers table? What I need on the application level is a list of the User objects contained in the SpecialUsers table.
How should I map the SpecialUsers table?
According to the structure of your USERS and SPECIALUSERS tables, you have a Table per subclass hierarchy and it is perfectly possible to map this kind of hierarchy with Hibernate.
First, make sure that SpecialUser inherits from User at the object model level (this is an inheritance relationship, not a self-reference).
public class SpecialUser extends User {
}
Then, declare a <joined-subclass> element in the User's mapping:
<hibernate-mapping package="com.initech.domain">
<class name="com.initech.User" table="USERS">
<id name="id" column="ID" type="java.lang.Long">
<meta attribute="use-in-tostring">true</meta>
<generator class="sequence">
<param name="sequence">SEQ_USERS_ID</param>
</generator>
</id>
<property name="loginName" column="LOGINNAME" type="java.lang.String" not-null="true">
<meta attribute="use-in-tostring">true</meta>
</property>
<joined-subclass name="com.initech.SpecialUser" table="SPECIALUSERS">
<key column="USERID"/>
</joined-subclass>
</class>
</hibernate-mapping>
What I need on the application level is a list of the User objects contained in the SpecialUsers table.
The following HQL query would return all the SpecialUser (which are User too):
from SpecialUser
If later you need to add columns to the SPECIALUSERS table, add the corresponding attributes to the SpecialUser class and map them inside the <joined-subclass> element. Refer to the provided link (to the documentation) for the details.
If you really have to use a second table, you must map it to a new class. Hibernate can always only map one table to one class.
Alternatively, add a column to the user table which says "this user is special". If that is not an option, create a view which joins the two tables and thus simulates this column. Then, you can select users by this column.
If you go the two class way, you must load a list of the special users and do the mapping in your application.
[EDIT] Maybe you should look into parent-child relations. In your case, the user is the parent and its roles are the children. So every user has 0..n roles which are mapped in a different table. You can then use this HQL
from User u where :role in elements(u.roles)
to find all users with a certain role. But most of the time, you'll have a specific user and just need to query whether she has a certain role.

Categories

Resources