hibernate criteria single object load - java

i have two entity(employeeTo & restTo) there is one-to-many relationship
between them,i want to get employee restTo list only, but when i load the list each of object contain employee object.
employeeTO
#OneToMany(mappedBy = "employeeTO",cascade = CascadeType.ALL)
private List<RestTO> RestTOList=new ArrayList<>();
restTO
#ManyToOne(fetch = FetchType.LAZY)
private EmployeeTO employeeTO;
and you can see my code below:
Session session = HibernateUtil.getSessionFactory().openSession();
Transaction transaction = session.beginTransaction();
Criteria criteria=session.createCriteria(RestTo.class);
criteria.setFetchMode("employeeTO",FetchMode.SELECT);
criteria.createAlias("employeeTO","alians_employee");
Criterion condition1= Restrictions.eq("alians_employee.emID",emid);
criteria.add(condition1);
criteria.add(Restrictions.between("startDate",date1,date2));
List<RestTO> restTOS=criteria.list();
transaction.commit();
session.close();
System.out.println(restTOS.get(0).getEmployeeTo.getName);
This instruction is working and show employee name
I want to not have access to employee object
i need load only RestTo object without employeeTo value.
how i can do it?
thanks.

Don't create an alias,it adss an inner join to your query. So instead of this
Criteria criteria=session.createCriteria(RestTo.class);
criteria.setFetchMode("employeeTO",FetchMode.SELECT);
criteria.createAlias("employeeTO","alians_employee");
Criterion condition1= Restrictions.eq("alians_employee.emID",emid);
Use this
Criteria criteria=session.createCriteria(RestTo.class);
//Default fetchmode is good,no need for that.
//criteria.setFetchMode("employeeTO",FetchMode.SELECT);
//criteria.createAlias("employeeTO","alians_employee");
Criterion condition1= Restrictions.eq("employeeTO.emID",emid);

Related

Hibernate - Adding properties of another class in Criteria Restrictions

I have a table Loan application whose pojo is
class LoanApplication{
int id;
int loanNo;
...
}
I have another pojo
class LoanFlow{
int id;
int loanId;
date reviewDate;
...
}
Here loanId of loanFlow is the foreign key mapped to the id of LoanApplication.
I have to fetch all the loan applications with the reviewDate.
I am trying to write a criteria like:
Criteria criteria = getSession().createCriteria(LoanApplication.class);
criteria.add(Restrictions.eq("id", someId));
How can I fetch the reviewDate also from LoanFlow with this criteria.
Criteria criteria = getSession().createCriteria(LoanApplication.class, "loApp");
criteria.createAlias("loApp.loanFlow", "flow");
criteria.add(Restrictions.eq("flow.id", 1));
You can directlly use HQL also.
using createQuery()
You can do it with subqueries, if there isn't ManyToOne or OneToMany annotations to the relationship between entities:
DetachedCriteria subQuery = DetachedCriteria.forClass(LoanFlow.class, "loanFlow");
/*Here there is a between, but you can change it to your necessity*/
subQuery.add(Restrictions.between("loanFlow.reviewDate", dateBegin, dateEnd));
subQuery.setProjection(Projections.property("loanFlow.loanId"));
Criteria criteria = getSession().createCriteria(LoanApplication.class, "loanApplication");
Subqueries.propertyIn("loanApplication.id", subQuery);
List<LoanApplication> list = criteria.list();

Hibernate: generate different (unique) IDs for same object reference in a list

Question
Is it possible to do an insertion in Hibernate when there is the same object reference twice in a list, I want to insert both of them and the ID has to be unique?
Background
I'm using random-beans to generate a random object Person which has a list of type House.
The problem is that random-beans doesn't create a new house object every time, it sometimes also uses existing references. In this case the same house object reference can be twice in the person's list.
But regardless of random-beans I would like to handle multiple references of new objects that have to be committed within the same transaction in Hibernate.
Probably this is not possible by the assignment of the ID at Session.save(Object obj), as there is still the same object referenced in the list. If there is no trivial solution to this, I would also be thankful for a way to just drop duplicated objects on save or commit. Note that changing the List to a Set doesn't solve the problem, as the same reference can be in different lists.
Example
The database is a MySQL database.
Main
Person steven = new Person();
House house1 = new House();
House house2 = new House();
steven.setHouses(new ArrayList<House>(Arrays.asList(house1, house2, house1));
Session session = getSessionFactory().openSession();
session.beginTransaction();
session.save(steven); // this is where I need to generate 3 different IDs
session.getTransaction().commit(); // this is where a duplicate entry exception is thrown
session.close();
Person
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id_person")
private int id;
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private List<House> houses;
House
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id_house")
private int id;
it is not possible, since you have just two instances. You need to create a copy or clone of house1
do something like : house3 = new House(house1);
session.persist() will create a new id for every object that you pass in. Please let me know if you hit issues.

Lazy loading collection of objects for insert with HQL

I need to load a collection of objects from DB via HQL with the purpose of using those objects only for setting an association in some new records.
Consider the following: I need to send an email to all students with nr of credits > 50 and I need to keep a trace of all the recipients included in the transmission.
First select the students:
Query query = sessionFactory.getCurrentSession().createQuery("from Student student left join fetch student.scores where student.credits>50");
List<Student> students = query.list();
this will return a list of students with all columns (non association attributes like first name, last name, date of birth...) loaded for each record.
The problem is that when I have a lot of data, the above query is very slow and occupies a lot of memory due to a large amount of useless data being transferred from db to app server.
I can't make all attributes lazy loaded directly in the entity as this will kill other areas of the application.
What I need is a way of loading the above collection with only the ids fetched as I am using the objects just to set them for some new objects in an association. I know this can be done for OneToMany associations easily but how can I do it for a direct queried collection?
List<Recipient> emailRecipients = new ArrayList<>();
for(Student student: students){
Recipient rec = new Recipient();
//this is the only usage of the student object
rec.setStudent(student);
...
set other properties for the recipient
sessionFactory.getCurrentSession().save(rec);
}
Inside the recipient, the Student object is setup like this:
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "STD_ID", nullable = false)
private Student student;
As you can see, only the id of the Student object is needed, but I don't know how to do it.
You can use one Hibernate specific trick, which allows you to set the FK association even if you don't provide an actual managed entity. Let's say we have a studentId, we can simply set:
Student student = new Student();
student.setId(studentId);
rec.setStudent(student);
This is not supported by standard JPA, but it works with Hibernate. Just make sure you don't have any cascade propagation from child to parent (which you should not have anyway).
In the end I've loaded the studentId only and modified the mapping inside the recipient to include the studentId as well:
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "STD_ID", insertable=false, updatable = false)
private Student student;
#Column(name = "STD_ID", nullable = false)
private Long studentId;
now I can simply set the studentId and the performance is much better.

Hibernate criteria using left join to filter results

JSF application with hibernate
Is there a way to use a join to filter the results returned by criteria list?
Example: i have 2 tables. orders and customers.
#Entity(name = "order")
public class Order
{
#Id
private int id;
private String billingCustomerId;
private String shippingCustomerId;
private Date orderDate;
....
}
#Entity(name = "customer")
public class Customer
{
#Id
private String id;
private String name;
private String emailAddress
....
}
I need to return all orders for customers that are missing an email address and all orders that the order.billingCustomerId = null and order.shippingCustomerId = null.
The customer could match on the billingCustomerId or shippingCustomerId.
The SQL I would use
select o.* from order as o
LEFT join customer as c1 on o.billingCustomerId = c1.id
LEFT join customer as c2 on o.shippingCustomerId= c2.id
where (o.billingCustomerId is null and o.shippingCustomerId is null) or
(o.billingCustomerId is not null and c1.emailAddress is null) or
(o.shippingCustomerIdis not null and c2.emailAddress is null)
Hibernate Criteria
Criteria criteria1 = session.createCriteria(Order.class);
criteria.add(Restrictions.and(Restrictions.isNull("billingCustomerId"),
Restrictions.isNull("shippingCustomerId"));
List<Order> = criteria.list();
This will return the list of orders that billing /shipping customer = null.
How can i change the criteria to also include the orders for customers with missing email addresses?
Disjunction disjunciton = Restrictions.disjunction();
Criteria criteria = session.createCriteria(Order.class);
disjunciton.add(Restrictions.and(Restrictions.isNull("billingCustomerId"),
Restrictions.isNull("shippingCustomerId")));
disjunciton.add(...
...)
criteria.add(disjunciton);
List<Order> = criteria.list();
I have not been able to find examples of joining on a column, but only where the table have a common key.
I asked this question: Hibernate trouble getting composite key to work and discovered Hibernate can only create a join on columns that were created by relating 2 objects. I am going to add more to my answer to give more useful information but the best alternative you your case is to do a Session.createSQLQuery() using the query you showed above. Then before running the query put Query.addEntity(Order.class).addEntity(Customer.class). As long as your query returns the correct rows to fill out the Java objects correctly, Hibernate can populate them automatically. If that doesn't work you can still retrieve the data and populate it manually yourself.

Hibernate join takes too long to work

Here is my problem:
I have this class it has few #oneToMany collections
public class ActivePropertyList implements Serializable
{
#OneToMany
#JoinTable(name = "PropertyAttributeLink",
joinColumns =
#JoinColumn(name = "EANHotelID"),
inverseJoinColumns =
#JoinColumn(name = "AttributeID", referencedColumnName="AttributeID"))
private Collection<AttributeList> attributeList;
#OneToMany(fetch= FetchType.LAZY)
#JoinColumn(name="EANHotelID")
private Collection<Hotelimageslist> hotelimageslist;
#OneToMany(fetch= FetchType.LAZY)
#JoinColumn(name="EANHotelID")
private Collection<Roomtypelist> roomtypelist;
//Getters & Setters ...
When I access this object from XHTML it takes too long to generate as I use <ui:repeat value=#{controller.ActivePropertyList.attributeList}> ...
PropertyAttributeLink has more than 5Mil rows and Images has more than 4Mil rows but when i use simple SQL query innerJoin i takes no more than few ms to generate Lists.
I've tried using namedQuery on AttributeList using HQL query but as AttributeList has no reference to ActivePropertyList as it is unidirectional #oneToMany it throws error on doing so.
Is there a way to create HQL NamedQuery to access each list just once and store it in controller?
something like
public List<AttributeList> getAttributeListByHotelID(int hotelID){
Query q = session().createQuery("from AttributeList AL inner join PropertyAttributeLink PA where PA.hotelID=:hotelID");
return q.list();
}
but this method doesn't work as hql needs AttributeList to know about PropertyAttributeLink
Pointing the joins just make the atributtes available for where conditions and other stuff, you should use FETCH to make the relations eager and have it inmediatly, avoiding the lazy iniciators, something like
from AttributeList AL inner join FETCH PropertyAttributeLink PA where PA.hotelID=:hotelID
As you see isn't so hard, i hope that helps you, you can get more information, as always, in the docs HQL - Associations and joins

Categories

Resources