How can I join two tables using JPA? - java

I have two entity classes Medicine and Medicine Group. A medicine belongs to a group . A group has more than one medicine. The relationship from medicine to group is one to one from group to medicine is one to many.
I have created the entity classes with the following properties
#Entity
public class Medicine {
#Id
String medicineId;
String medicineName;
int inStock;
String lifetimeSupply;
String lifetimeSales;
String howToUse;
String sideEffects;
//their getters and setters
}
#Entity
public class MedicineGroup {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
int groupId;
String groupName;
String groupDescription;
//their getters and setters.
}
In MySQL in the Medicine table I have a column called groupId which is a foreign key to the group table.
Normally in MySQL I could write a join statement like this
SELECT medicine_id ,medicine_name ,in_stock ,lifetime_supply, lifetime_sales, how_to_use, side_effects , group_name FROM medicine JOIN medicine_group on medicine.group_id = medicine_group.group_id;
In the above join I am able to get the group name column from the group table. How can I achieve this using JPA.
If I add a field to the medicine class like this
#OneToOne
MedicineGroup medicineGroup;
when I do a get request I get an error Unknown column 'medicine0_.medicine_group_group_id' in 'field list' . How is the field unknown yet I have a column called group_id in the medicine table?
How can I achieve a way in which if I perform a get request I get the medicine information and also the group with which it is associated with? Please help.

Simple join on the attribute:
SELECT m.medicineId ,m.medicineName ,m.inStock ,m.lifetimeSupply, m.lifetimeSales, m.howToUse, m.sideSffects , mg.groupName
FROM medicine m join m.medicineGroup mg;
and use attribute names, not column names

select m from medicine m left join fetch m.medecineGroup

Related

How Can I write The Following Query In hibernate Criteria

Select * from Table A left join Table B on A.id=B.id and A.langCode='IN';
where 'IN' is input from user.
Table A and Table B has Mapping For Id but there is no Mapping with LangCode between the two as table B dosent have an column called langCode to map with , i want to write the following query using hibernate criteria without mapping langcode.
Table: Employee :
EMP_ID - primary key ,
NAME ,
CONTACT_DETAILS
Table:Employee_Lang:
EMP_ID- composite primary key,
LANG_CODE- composite primary key,
NAME
Actual Query:
Select * from Employee Emp left outer join Employee_Lang EmpLang on Emp.EMP_ID=EmpLang.EMP_ID AND EmpLang.LANG_CODE='IN'
I have mapped only the Emp_Id as primary key from both the tables in hibernate hence hibernate criteria will only apply a join on that
And not on LangCode.
Note:-I cant change hibernate mapping and can use only hibernate Criteria , as per the clients requirement, please help me on this one.
For example you have two models:
#Entity
class Employee {
#Id
private Long id;
#OneToOne
private EmployeeLang employeeLang;
...
}
#Entity
class EmployeeLang {
#Id
private Long id;
private String langCode;
#OneToOne
private Employee employee;
...
}
You should have some mapping between them and then you can do next criteria:
Criteria criteria = session.createCriteria(Employee.class);
criteria.createAlias("employeeLang", "empLang"); // inner join with EmployeeLang
criteria.add(Restrictions.eq("empLang.langCode", "in");
List<Employee> employees = criteria.list();

Hibernate: mapping collection property with alternate join column

Scenario: Hibernate 3.6 with xml-based mapping, Java7, Postgresql 8.3.
I'm currently refactoring an application where I have got this scenario for the database:
main_table
id integer
other_field string
(id) PK
secondary_table
other_field string
value string
(other_field, value) PK
Basically, there's a secondary table which contains an "other_field" which is matched on the main table; I need to extract all values for a certain record in main_table and map them.
In SQL I'd use a query like:
SELECT value FROM secondary table INNER JOIN main_table ON secondary_table.other_field == main_table.other_field where main_table.id = 1;
But I don't understand how to map a collection of basic types (strings) to the Main object in Java using such a query (or a similar one if the one I propose is not hibernate friendly), so that I can have a "values" property on my mapped object, which should be a Set<String>
I think this is what you are looking for:
#Entity
public class Primary { // Main table
#Id
#Column(name="EMP_ID")
private long id;
...
#ElementCollection
#CollectionTable(
name="PRIMARY_SECONDARY",
joinColumns=#JoinColumn(name="PRIMARY_ID")
)
private Set<Secondary> phones;
...
}
#Embeddable
public class Secondary { // Secondary table
private String value;
...
}
Full example and further details.

Implementing hierarchical data structures with JPA (fixed depth)

I have a hierarchical data structure with a fixed depth of 4. For a better understanding, let's assume the following (just an example):
The "root" level is called countries
Each country contains an arbitrary amount of states
Each state countains an arbitrary amount of counties
Each county contains an arbitrary amount of cities
So there are always 1-N relationships between the levels.
A very important usecase (given the id of a country) is to load the whole "content" of a country at once with the smallest possible impact on the performance of the database.
In a first naive approach, I created 4 entitiy classes in Java where the entity "Country" contains a list of the type "State", the entity "State" contains a list of the type "County" and so on...
But what JPA creates afterwards are of course not 4 tables, but 7 (4 for the entities + 3 for the connection between the levels due to 1-N). I don't know if this is a good solution since there is a lot of joining going on under the hood.
I also tried to map the subtypes to their parent types (a city belongs to one county, a county belongs to one state, a state belongs to one country). This results in 4 tables, but makes it more difficult to retrieve all data at once from the application's point of view. If I'm not wrong, I would need 4 different requests instead of one.
How could I solve this problem? Is there a way to combine a simple table layout (with four tables, not seven) with easy to use entity classes (a parent type should know its children)?
If not, how would you realize this?
I'm using JPA with Hibernate and PostgreSQL.
You can avoid the 3 extra mapping tables by using the #JoinColumn annotation rather than the #JoinTable annotation that I suspect you are using.
So for example:
COUNTRY
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy="country")
private List<State> stateList;
STATE
#ManyToOne
#JoinColumn(name="country_id")
private Country country
The database tables would be as follows:
Country
country_id => primary key
State
state_id => primary key
country_id => foreign key
This way the mapping tables between all the 4 entities can be avoided.
You can achieve this pretty easily using JPQL:
SELECT DISTINCT country
FROM Country country
JOIN FETCH country.states states
JOIN FETCH states.counties counties
JOIN FETCH counties.cities cities
WHERE country.id = :countryId
Using fetchType = FetchType.EAGER on #OneToMany/#ManyToOne(believe that one is already EAGER by default) will achieve similar results.
It's very simple use bidirectional mapping. Go through that link
How to delete Child or Parent objects from Relationship?
Make some changes like below
Country Entity:
------
#OneToMany(mappedBy="Country ",cascade = CascadeType.ALL)
private List<States > states;
#OneToMany(mappedBy="Country ",cascade = CascadeType.ALL)
private List<Counties> counties;
#OneToMany(mappedBy="Country ",cascade = CascadeType.ALL)
private List<Cities> cities;
-------
setters & getters
States Entity:
-----
#ManyToOne(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
#JoinColumn(name="countryId")
private Country country ;
-----
Counties Entity:
--------
#ManyToOne(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
#JoinColumn(name="countryId")
private Country country ;
-------
Cities Entity:
#ManyToOne(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
#JoinColumn(name="countryId")
private Country country ;
---------
After compilation of all entity's do your insertion . Only 4 will create and read your data by using Country object id.
You already have the solution: four table is the way to go, with bidirectional relationships (use the mappedBy property in the not-owning side of every relationship). If the relationships are EAGER-fetched, than all entities are automatically loaded. If you want to use LAZY fetching, you could try a named query in order to load the entity with all relationships loaded:
SELECT DISTINCT c FROM Country c LEFT JOIN FETCH c.states s LEFT JOIN FETCH s.counties co...
Did you try to declare the fetch type of the relations explicitely to eager with your second approach (default is lazy, that's why you have to do four queries).
E.g.
#OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
#JoinColumn ...
private ...;
see here: http://www.concretepage.com/hibernate/fetch_hibernate_annotation
Here is how your entities will look like:(You can use EAGER Loading instead of LAZY as well if you want)
Entity: Country
#Id
private Integer id;
#OneToMany(orphanRemoval=true fetch=FetchType.LAZY)
#JoinColumn(name="COUNTRY_ID")
private List<State> stateList;
Entity: State
This table has COUNTRY_ID that is Foreign Key to Country
#Id
private Integer id;
#OneToMany(orphanRemoval=true fetch=FetchType.LAZY)
#JoinColumn(name="STATE_ID")
private List<County> countyList;
#Column(name="COUNTRY_ID")
private Integer countryId;
Entity: County
This table has STATE_ID that is Foreign Key to State
#Id
private Integer id;
#OneToMany(orphanRemoval=true fetch=FetchType.LAZY)
#JoinColumn(name="COUNTY_ID")
private List<City> cityList;
#Column(name="STATE_ID")
private Integer stateId;
Entity: City
This table has COUNTY_ID that is Foreign Key to County
#Id
private Integer id;
#Column(name="COUNTY_ID")
private Integer countyId;
Your JPQL will be:
Select o from Country o where o.id=10
This will pick The Country Entity along with all the mappings like below.
Country
Holding List of States
Each States Holding List of Counties
Each Counties Holding LIst of Cities
For a requirement like yours, I would suggest to have a tree-like structure to maintain the hierarchical location data. It is relatively easy to implement & maintain and is more scalable & extensible.
In order to implement tree you need to have 2 tables LOCATION_NODE (Location ID, Location Name, Location Type[country, state, county, city]) & LOCATION_REL (Relation ID, Parent ID, Child ID). Below is the basic implementation of the tree idea.
public class LocationRel<T> {
private LocationNode<T> root;
public LocationRel(T rootData) {
root = new LocationNode<T>();
root.data = rootData;
root.children = new ArrayList<LocationNode<T>>();
}
public static class LocationNode<T> {
private T data;
private LocationNode<T> parent;
private List<LocationNode<T>> children;
}
}
This is the basic building block for a tree. You may need to add methods for add to, removing from, traversing, and constructors. But, once implemented, you have the freedom to add any new location type, change the hierarchy, add node, delete node etc with your hierarchical data.
Think out of the box.
Shishir
If you need the performance, I would suggest to de-normalize your tables and create 4 entities with following attributes (columns):
Country: id, name
State: id, countryId, name
County: id, countryId, stateId, name
City: id, countryId, stateId, countyId, name
(mapping is obvious)
Then you will be able to build a simple SQL queries.
If you need performance, prefer named queries as they are compiled at initialization time.
E.g. select all cities by country: "SELECT id, name FROM city WHERE country_id=?"
You may even not declare a references between entities using #ManyToOne, but just declare a simple #Columns. API call will, most likely, accept IDs (countryId, stateId), so you'll be better to pass that IDs as parameters to DAO. Most likely, you have a locations tables filled in once by sql script and the data should not be modified. Create foreign keys to guarantee data integrity.
And do you really need a tree-like structure in memory? If so, create it by hand, it is not very complex.
Searching Online, I found a couple of Links on JPQL which I think might help.
Link 1
Link 2
Anyways,
JPQL is one of the best ways to achieve this, try out this Query
SELECT DISTINCT country FROM Country country JOIN FETCH country.states states JOIN FETCH states.counties counties JOIN FETCH counties.cities cities WHERE country.id = :countryId
A solution that is useful, if you have relations that point to their parent only is the following:
With records:
#Entity
public class Country
{
#Id
private Long id;
}
#Entity
public class State
{
#Id
private Long id;
#ManyToOne(optional = false)
#JoinColumn(name = "country_id", referencedColumnName = "id", nullable = false)
Country country;
}
#Entity
public class County
{
#Id
private Long id;
#ManyToOne(optional = false)
#JoinColumn(name = "state_id", referencedColumnName = "id", nullable = false)
State state;
}
#Entity
public class City
{
#Id
private Long id;
#ManyToOne(optional = false)
#JoinColumn(name = "county_id", referencedColumnName = "id", nullable = false)
County county;
}
You can get all cities of a country with:
public interface CityRepository extends JpaRepository<City, Long>
{
List<City> findByCounty(County county); // county is a direct field of City
#Query("SELECT c FROM City c WHERE c.county.state.country = ?1")
List<City> findByCountry(Country country);
}

Hibernate Criteria Join problem

I have a 2 classes that share a UUID and are uni-directionally mapped. I use the UUID to group related rows, and this group shares many details (this is just an example):
#Entity #Table
class Something {
#Id #Column("something_id")
private Long id;
private String uuid = UUID.randomUUID().toString();
#OneToMany
#JoinColumn("uuid")
private List<Detail> details = new LinkedList<Detail>();
}
#Entity #Table
class Detail {
#Id #Column("detail_id")
private Long id;
private String value;
private String uuid;
}
I'm attempting to use Criteria:
Criteria c = getSession().createCriteria(Something.class).createAlias("details", "detail").add(Restrictions.eq("detail.value", someValue));
This is all fine and dandy, but I'm not getting results because of the join:
inner join DETAIL d1_ on this_.SOMETHING_ID=d1_.UUID
Is it possible to specify:
inner join DETAIL d1 on this_.UUID=d1.UUID
I would have expected the join to use the #JoinColumn annotaiton to find the column to join on. I see that I can specify a join type, but I don't see a way to specify the actual column.
I would have expected the join to use the #JoinColumn annotation to find the column to join on. I see that I can specify a join type, but I don't see a way to specify the actual column.
The join is using the JoinColumn annotation since it's joining on d1_.UUID. However, because you didn't specify the referencedColumnName element, the foreign key is assumed to refer to the primary key of the referenced table (this_.SOMETHING_ID), hence the obtained result.
In other words, try this:
#OneToMany
#JoinColumn(name="uuid", referencedColumnName="uuid")
private List<Detail> details = new LinkedList<Detail>();
I'm not sure to understand the benefit but let's say it's another story.

Basic Hibernate/JPA Mapping question

I have to tables I want to map to each other.
I want to populate 2 drop down lists: code_r and code_l.
When i choose a value from code_r, code_l should display only certain records.
In my database I have 2 tables:
Table code_r
===================
CODE INT
LIBELLE VARCHAR
And
Table code_l
===================
ID BIGINT
CODE_R_ID INT
LIBELLE VARCHAR
One code_r can have multiple code_l associated with it (based on the code_r_id (not a defined as a Foreign key in the code_l definition). Of course, a code_l can only be associated to one code_r.
The following SQL query works fine:
SELECT *
FROM code_r r
left join `code_l` l on l.code_r_id = r.code;
How should I implement that using using JPA/Hibernate-3.5 annotations in the CodeR and CodeL classes??
Any help would be appreciated. Thanks in advance.
With Hibernate (and now standardized in JPA 2.0), you can use a unidirectional one-to-many association without a join table using a JoinColumn annotation:
Annotate the CodeR like this:
#Entity
public class CodeR {
#Id
private Integer code;
private String libelle;
#OneToMany
#JoinColumn(name="CODE_R_ID")
Set<CodeL> codeLs = new HashSet<CodeL>():
// getters, setters
}
And CodeL
#Entity
public class CodeL {
#Id
private Integer id;
private String libelle;
// getters, setters, equals, hashCode
}
And the JPQL query:
SELECT r FROM CodeR LEFT JOIN r.codeLs
in the CodeR class:
#OneToMany(mappedBy="code_r_id")
Collection elementsFromL;
in the CodeL class:
#ManyToOne
CodeR code_r_id;

Categories

Resources