Hibernate Mapping - Join of two table to one flat class - java

I have two tables: patient_data and patient_diagnosis
Patient_data contains personal data of patient like: pid (pkey), gender, birth_date
patient_diagnosis contains the diagnosis data of the registered patients. It has fields like: record_id (pkey), pid (fkey to patient_data(pid)), diagnosis_date and other related fields.
Now, I want to join these two tables on pid and have all these fields in a single type of object.
Here is the mapping file:
<hibernate-mapping>
<class catalog="emr" name="in.Models.Emr" table="patient_diagnosis">
<id name="recordid" type="long">
<column name="record_id"/>
</id>
<property name="diagnosisDate" type="timestamp">
<column length="19" name="diagnosis_date" not-null="true"/>
</property>
<property name="snomedTermPrimary" type="long">
<column name="snomed_term_primary" not-null="true" />
</property>
<property name="snomedTermSecondary" type="string">
<column name="snomed_term_secondary" />
</property>
<property name="episodeNo" type="long">
<column name="episode_no" not-null="true" />
</property>
<property name="pid" type="long">
<column name="pid" not-null="true" />
</property>
<join table="patient_data">
<key column="pid"/>
<property name="gender" type="string">
<column name="gender" not-null="true"/>
</property>
<property name="birthDate" type="timestamp">
<column length="19" name="birth_date" not-null="true"/>
</property>
</join>
</class>
</hibernate-mapping>
But, the join applies on patient_diagnosis.record_id = patient_data.pid instead of patient_diagnosis.pid = patient_data.pid i.e. HQL applies on primary key of first table with mentioned column from second table.
Please provide the solution so that join can be applied on mentioned column from first with mentioned column from second table. Or is there another way out?
Please note that in case I didn't create classes for patient_data or patient_diagnosis. But, just Emr class having combination of fields of these tables is created.

Try giving foreign key
<id name="pid" type="java.lang.Long">
<column name="pid" />
<generator class="foreign">
<param name="property">patient_data</param>
</generator>
</id>
I am not sure but maybe this should work.
And
<one-to-one name="patient_data" class="in.Models.Emr"
cascade="save-update"></one-to-one>
Similarly in Join class
<one-to-one name="patient_diagnosis" class="in.Models.Emr"
cascade="save-update"></one-to-one>
I hope this helps you.

Related

HIbernate mapping on the wrong froreign key

I have 2 classes Device and Position that have a relation one-to-many/many-to-one (One device has several positions, a position is associated to one and only one device).
I have clearly specified in the hibernate mapping file that I want my table to join on device.DeviceID = position.FK_DeviceID, yet when i execute the following HQL query:
String queryString = "select position"
+ " from Position position join position.device device"
+ " where device.MACAddress = '" + macAddress + "'";
I keep getting the error : " ERROR: Unknown column 'position0_.deviceID' in 'field list' ", indicating me that he tries to join on "deviceID" and not "FK_deviceID".
Here are the classes and the mapping files:
Position:
private Integer positionID;
private Coordinate coordinate;
private Date timestamp;
private Device device;
Device:
private Integer deviceID;
private String MACAddress;
private String name;
private Set<Position> positions;
Device mapping:
<hibernate-mapping>
<class name="fr.utbm.LO53_IPS.models.Device" table="device" catalog="bdd_LO53">
<id name="deviceID" type="java.lang.Integer">
<column name="deviceID" />
<generator class="identity" />
</id>
<property name="MACAddress" type="string">
<column name="MACAddress" length="45" not-null="true"/>
</property>
<property name="Name" type="string">
<column name="Name" length="45" not-null="false" />
</property>
<set name="positions" cascade="all">
<key column="FK_DeviceID"/>
<one-to-many class="fr.utbm.LO53_IPS.models.Position" />
</set>
</class>
Position mapping:
<hibernate-mapping>
<class name="fr.utbm.LO53_IPS.models.Position" table="position" catalog="bdd_LO53">
<id name="PositionID" type="java.lang.Integer">
<column name="deviceID" />
<generator class="identity" />
</id>
<property name="Timestamp" type="java.sql.Date">
<column name="Timestamp" not-null="true"/>
</property>
<many-to-one name="device" column="FK_DeviceID"
class="fr.utbm.LO53_IPS.models.Device" not-null="true"/>
<component name="Coordinate" class="fr.utbm.LO53_IPS.models.Coordinate">
<property name="x" type="java.lang.Integer">
<column name="x" not-null="true" />
</property>
<property name="y" type="java.lang.Integer">
<column name="y" not-null="true" />
</property>
</component>
</class>
Sorry for the long post, I really can't figure out what part is wrong.
In the mapping for class Position, when you declare the id you are specifying a column called deviceID, which is a bit strange, because you should have a column PositionID, since you are in the table Position.
On the other hand, you can easily join like this: from Position p where p.device.MACAddres='....' without using join explicitly.

Hibernate - load children

I have the following Hibernate Mappings:
<class name="Database.Content" table="..." schema="" catalog="...">
<id name="id">
<column name="id" sql-type="int" not-null="true"/>
</id>
<property name="week">
<column name="week" sql-type="int"/>
</property>
<property name="day">
<column name="day" sql-type="int"/>
</property>
<property name="hour">
<column name="hour" sql-type="int"/>
</property>
<property name="type">
<column name="type" sql-type="int" not-null="true"/>
</property>
<many-to-one name="group" class="Database.Group">
<column name="group"/>
</many-to-one>
<many-to-one name="table" class="Database.Table">
<column name="table" not-null="true"/>
</many-to-one>
<list name="entries" inverse="true" table="...">
<key>
<column name="content" not-null="true"/>
</key>
<list-index column="id"/>
<one-to-many not-found="ignore" class="Database.Entry"/>
</list>
</class>
<class name="Database.Entry" table="..." schema="" catalog="...">
<id name="id">
<column name="id" sql-type="int" not-null="true"/>
</id>
<property name="teacher">
<column name="teacher" sql-type="int" not-null="true"/>
</property>
<property name="course">
<column name="course" sql-type="int" not-null="true"/>
</property>
<property name="room">
<column name="room" sql-type="int" not-null="true"/>
</property>
<property name="p">
<column name="p" sql-type="int" not-null="true"/>
</property>
<many-to-one name="content" class="Database.Content" fetch="join" lazy="false">
<column name="content" not-null="true"/>
</many-to-one>
</class>
Now I am trying to query all contents with the corresponding entries:
List<Content> contents = session.createQuery("from Content c WHERE c.day IN :days ").setParameterList("days", days).list();
The query returns the correct response. However, when I do the following:
contents.get(0).getEntries()
there is a bunch of null values. What is the correct way to eager load all corresponding entries for each content?
I have about 20,000 content records, and most of the records have only one entry.
If I set lazy="false" for the list of entries, I get Java heap space error.
I ended up fetching entries and joining contents:
List<Entry> entries = session.createQuery("select e from Entry e Join e.content c WHERE c.day IN :days ").setParameterList("days", days).list();
I also changed lazy to proxy in:
<many-to-one name="content" class="Database.Content" fetch="join" lazy="proxy">
<column name="content" not-null="true"/>
</many-to-one>
Add lazy=false attribute:
<list name="entries" inverse="true" table="up_timetable_entries" lazy="false">
Hope helped you!
Try calling:
contents.get(0).getEntries().size();
To force hibernate to load the children.

org.hibernate.exception.MappingException or ConstraintViolation

I am using hibernate 4.1.9. I have Users, and the Users have a list of Accounts, and Accounts have list of Transactions. Here is my hbm.xml
<?xml version="1.0"?>
<class name="User" table="users">
<id name="userId" column="userid">
<generator class="increment"/>
</id>
<property name="username" column="username" not-null="true"/>
<property name="password" column="password" not-null="true"/>
<property name="registerDate" type="timestamp" column="register_date"/>
<list name="accounts" table="accounts" inverse="true" cascade="all">
<key column="userid" not-null="true"/>
<index column="accountid"/>
<one-to-many class="com.joe.data.Account"/>
</list>
</class>
<class name="Account" table="accounts">
<id name="accountId" column="accountid">
<generator class="increment"/>
</id>
<property name="balance" type="big_decimal" column="balance"/>
<property name="lastModified" type="timestamp" column="last_modified"/>
<list name="txns" table="transactions" inverse="true" cascade="all">
<key column="accountId" not-null="true"/>
<index column="transactionId"/>
<one-to-many class="com.joe.data.Transaction"/>
</list>
<many-to-one name="userId" class="User" column="userid" not-null="true"
unique="true" cascade="all"/>
<many-to-one name="accountType" class="AccountType" column="account_type"
not-null="true" cascade="all" unique="true" />
</class>
<class name="Transaction" table="transactions">
<id name="transactionId" column="transactionid">
<generator class="increment"/>
</id>
<property name="description" column="description"/>
<property name="amount" type="big_decimal" column="amount"/>
<property name="dateAdded" column="date_added"/>
<property name="reoccuring" type="numeric_boolean" column="reoccuring"/>
<many-to-one name="category" class="Category" column="category"
not-null="true" cascade="all" unique="true" />
</class>
<class name="Category" table="categories">
<id name="categoryId" column="categoryid"/>
<property name="categoryName" column="categoryname" not-null="true"/>
</class>
<class name="AccountType" table="account_types">
<id name="accountType" column="account_type"/>
<property name="accountName" column="name"/>
</class>
If I leave inverse="true" on the list of accounts (in the User) I get the ConstraintViolationException because the userid is not getting put in the insert query. If I take inverse="true" off of the list of accounts, I get org.hibernate.MappingException: Repeated column in mapping for entity: com.joe.data.Account column: accountid (should be mapped with insert="false" update="false")
To clarify lowercase names are database columns names, camel case are class variable names. I know Transaction class isn't working quite right yet, but if I could get the Accounts to insert I could do the same thing to get the Transactions to insert.
Edit: I added the many-to-one on the Account class and now I am getting another exception where hibernate is complaining about missing a getter for userId in com.joe.data.Account
In order to get inverse="true" work, you need to define many-to-one for User in Account and for Account in Transaction class and mappings.

Making join with Criteria

I'm terribly new to Hibernate. I've googled for two hours but I still can't figure out, how to make JOIN without using HQL, only by criteria. I have tables Clients(cID, name) and Visits(vID, vcID, date). The relation is one to many (one client can visit multiple times). I would also like to do it without setFetchMode. Just Criteria. Do I have to change the mappping xml?
UPDATE:
this is part of my mapping xml:
<class name="Client" table="Clients">
<id name="cID" column="cID"><generator class="native"/></id>
<property name="name" length="10" not-null="true"/>
</class>
<class name="Visit" table="Visits">
<id name="vID" column="vID"><generator class="native"/></id>
<property name="vcID" length="10" not-null="true"/>
<property name="date" length="25" not-null="true"/>
</class>
Having a class Client with a list-attribute "visits" that's mapping to your Visit-Entity:
Criteria criteria = session.createCriteria(Client.class);
criteria.addCriteria("visits");
This would create an inner join between your client-table and your visits-table.
Update:
Here you'll find some good examples: http://docs.jboss.org/hibernate/orm/3.3/reference/en/html/querycriteria.html#querycriteria-associations
Mapping Example
I hardly ever use hibernate mapping xml, however it should read similiar to:
<class name="Client" table="Clients">
<id name="cID" column="cID"><generator class="native"/></id>
<property name="name" length="10" not-null="true"/>
<bag name="visits">
<key column="vcId"/>
<one-to-many class="Visit"/>
</bag>
</class>
Tell Hibernate that there is a property "visits" which represents a one-to-many relationship.
You need to update you mapping:
<class name="Client" table="Clients">
<id name="cID" column="cID"><generator class="native"/></id>
<property name="name" length="10" not-null="true"/>
<!-- Declare Set<Visit> visits in the Client class-->
<set name="visits" lazy="false" cascade="all">
<key column="vcID"/>
<one-to-many class="your.package.Visit"/>
</set>
</class>
<class name="Visit" table="Visits">
<id name="vID" column="vID"><generator class="native"/></id>
<!-- and add "Client client" property to your Visit class -->
<many-to-one name="client" column="vcID" lazy="false"/>
<property name="date" length="25" not-null="true"/>
</class>
Then:
Criteria criteria = session.createCriteria(Visit.class).addCriteria("client")
.add(Restriction.eq(...));
or
Criteria criteria = session.createCriteria(Client.class).addCriteria("visits")
.add(Restriction.eq(...));
And Hibernate will join them automatically.

Insert into join table in many-to-many relationship

Problem #1:
I have three tables; User, UserRole, and UserRoleRelationships (join table). The UserRole table contain all the user roles which I want to associate with the user. When I insert a new user I want to add a new user and add a new association in the join table. Now, when I'm running the query for inserting a new user:
IWUser iwUser = new IWUser();
iwUser.setUsername("username");
iwUser.setFullName("fullName");
iwUser.setEmail("email");
iwUser.setPassword("password");
iwUser.setPrivatephone("55555");
iwUser.setWorkphone("777");
Set<IWUserRole> roleList = new HashSet<IWUserRole>();
IWUserRole iwUserRole = new IWUserRole();
iwUserRole.setRole("ROLE_USER");
roleList.add(iwUserRole);
iwUser.setUserRole(roleList);
iwUserManagementService.saveOrUpdate(iwUser);
hibernate is running the following queries:
Hibernate: insert into dbo.Users (Username, Password, Email, Workphone, Privatephone, FullName) values (?, ?, ?, ?, ?, ?)
Hibernate: insert into dbo.UserRoles (Role) values (?)
Hibernate: insert into UserRoleRelationships (UserId, RoleId) values (?, ?)
My hibernate mapping looks like:
IWUser.hbm.xml:
<hibernate-mapping>
<class name="domain.IWUser" schema="dbo" table="Users">
<id name="userId" type="int">
<column name="UserId"/>
<generator class="native"/>
</id>
<property name="username" type="string">
<column name="Username" not-null="true"/>
</property>
<property name="password" type="string">
<column name="Password" not-null="true"/>
</property>
<property name="email" type="string">
<column name="Email" not-null="false"/>
</property>
<property name="workphone" type="string">
<column name="Workphone" not-null="false"/>
</property>
<property name="privatephone" type="string">
<column name="Privatephone" not-null="false"/>
</property>
<property name="fullName" type="string">
<column name="FullName" not-null="false"/>
</property>
<set cascade="all" inverse="false" name="userRole" table="UserRoleRelationships" lazy="true" >
<key>
<column name="UserId"/>
</key>
<many-to-many class="domain.IWUserRole" column="RoleId"/>
</set>
</class>
</hibernate-mapping>
IWUserRole.hbm.xml:
<hibernate-mapping>
<class name="domain.IWUserRole" schema="dbo" table="UserRoles">
<id name="roleId" type="int">
<column name="RoleId"/>
<generator class="native"/>
</id>
<property name="role" type="string">
<column name="Role" not-null="true"/>
</property>
<set cascade="all" inverse="false" name="user" table="UserRoleRelationships" lazy="true">
<key>
<column name="RoleId"/>
</key>
<many-to-many class="domain.IWUser" column="UserId"/>
</set>
</class>
</hibernate-mapping>
How can I get hibernate to save the new user with an existing user role in the join table?
Problem #2:
When I update the user, hibernate delete the relations in the join table. How can I avoid this?
How can I get hibernate to save the new user with an existing user role in the join table?
Retrieve the user role entity and put that into the list instead of always creating a new one.
I mean this part:
IWUserRole iwUserRole = new IWUserRole();
iwUserRole.setRole("ROLE_USER");
Instead, you'd issue a query like select r from IWUserRole where r.role = 'ROLE_USER'

Categories

Resources