I am using a JPA query to get a result set, then within the same class, I would like to conditionally get more data. Here's what it looks like:
public SchoolUser getCandidatesAsJson(#PathParam("applicationId") String applicationId, #PathParam("userPassword") String userPassword ) {
EntityManager em = createEM();
Query query = em.createQuery("SELECT su FROM SchoolUser su WHERE su.applicationId LIKE :applicationId and su.userPassword LIKE :userPassword", SchoolUser.class);
query.setParameter("applicationId", applicationId);
query.setParameter("userPassword", userPassword);
List <SchoolUser> schoolUser = query.getResultList();
if(!schoolUser.isEmpty()) {
SchoolUser loginRecord = schoolUser.get(0);
int teacherId = loginRecord.getTeacherId();
int studentId = loginRecord.getStundentId();
if(teacherId!=0){
TypedQuery<Classroom> query2 = em.createQuery("SELECT c FROM Classroom c where c.teacherId = :teacherId ORDER BY c.period", Classroom.class);
query2.setParameter("teacherId", teacherId);
List <Classroom> teacherClassList = query2.getResultList();
if(!teacherClassList.isEmpty()){
//put 2nd results set in SchoolUser object - line is commented because it causes an erro
//loginRecord.setClassRooms(teacherClassList);
}
} else if(studentId!=0){
TypedQuery<ClassroomStudent> query3 = em.createQuery("SELECT cs FROM ClassroomStudent cs where cs.statusId = 1 AND cs.studentId = :studentId", ClassroomStudent.class);
query3.setParameter("studentId", studentId);
//put results in SchoolUser object
}
return loginRecord;
} else {
SchoolUser emptyRecord = new SchoolUser();
return emptyRecord;
}
}
The error comes from putting the Classroom JPA object into the SchoolUser object - since these two objects don't have a direct relationship.
Any way that I can accomplish this with JPA?
If you do not want to persist the classroom (or any other attribute for that matter) then the #Transient annotation allows you to ignore a particular field so that JPA won't try to map it.
This annotation specifies that the property or field is not
persistent. It is used to annotate a property or field of an entity
class, mapped superclass, or embeddable class.
Example:
#Entity
public class Employee {
#Id int id;
#Transient User currentUser;
...
}
Related
I need to fetch 6 columns by joining 3 different tables. I have declared them as NamedNativequery on top of the entity class and I have used create named query method form JPA. When I try fo fetch the result set i get the list of array objects instead of the List of objects of POJO type. is there any external mapping should I be defining in order to map the result set to an external POJO?
You certainly can. This should help:
#NamedNativeQuery(query = "SELECT t1.col1, t2.col2 FROM t1 JOIN t2 ON ...", name = "MyNamedQuery", resultSetMapping = "MyPojoMapper")
#SqlResultSetMapping(name = "MyPojoMapper", classes = #ConstructorResult(
targetClass = MyPojo.class,
columns = {
#ColumnResult(name = "col1", type = String.class),
#ColumnResult(name = "cols", type = String.class)
}))
Then use it as such:
NativeQuery query = session.getNamedNativeQuery("MyNamedQuery");
MyPojo result = (MyPojo) query.getSingleResult();
You can use projection to specify what properties you want to get
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#projections
or directly get with JPQL:
Repository.java
#Repository
public class CustomRepositoryImpl {
#Autowired
private EntityManager entityManager;
public List<Dto> find() {
var query = "SELECT new Dto(
x.Field1,
y.Field2,
z.Field3,
...)
FROM XxxEntity x
LEFT JOIN YyyEntity y
LEFT JOIN ZzzEntity z"
var jpqlQuery = entityManager.createQuery(query);
return jpqlQuery.getResultList();
}
}
Dto.java
public class Dto {
// Must have parameterized constructor with all fields what used in Repository
public Dto(int field1, String field2, String field3, ...) {
}
}
I want to use this HQL query in order to select table row value:
String hql = "select e.token, e.name from Terminals e where e.token = ?";
Terminals terminal = entityManager
.createQuery(hql, Terminals.class)
.setParameter(0, terminalToken)
.getSingleResult();
But I get this result:
java.lang.IllegalArgumentException: Cannot create TypedQuery for query with more than one return using requested result type [org.api.entity.Terminals]
What is the proper way to implement this?
Your query return two Objects token and name and not a Terminals Object.
Instead you can use :
Object[] obj = entityManager
.createQuery(hql)
.setParameter(0, terminalToken)
.getSingleResult();
if(obj != null){
Terminals terminal = new Terminals((String) obj[0], (String) obj[1]);
}
Or you can create a constructor in Terminals class which hold two fields :
public Terminals(String token, String name){
this.token = token;
this.name = name;
}
then change your code to be :
String hql = "select new com.package.Terminals(e.token, e.name) from Terminals e where e.token = ?";
Terminals terminal = entityManager
.createQuery(hql, Terminals.class)
.setParameter(0, terminalToken)
.getSingleResult();
IMO, you should not directly call createQuery to assign to a custom object. And there is a possiblity of returning a list.
Query query = entityManager.createQuery(hql).setParameter(0, "something");<br>
List<Object[]> terminals = query.getResultList();
and retrieve the objects with an index as the ff as an example:
StudentDto dto = new StudentDto();
for(Object[] a: std) {
dto = new StudentDto();
dto.setId((long) a[0]); //id
dto.setName(a[1].toString()); //first name
dto.setPassportNumber(a[2].toString()); //last name
}
Example classes:
public Class Order{
private Integer id;
private Customer customer;
}
public Class Customer{
private Integer id;
private String name;
}
Example query that I want to execute in PostgreSQL syntax:
SELECT order_alias.id
FROM (select * from order where customer is not null) order_alias
WHERE order_alias.customer < 10;
How can I do this in Hibernate?
The reason I'm asking this is because Hibernate seems to be throwing an "Unknown entity: null" error when the customer property is null.
This is what I was trying to do with Criteria:
DetachedCriteria dc = DetachedCriteria.forClass(Order.class, "o");
dc.add(Restrictions.lt("o.customer.id", 10);
dc.setProjection(Projections.property("o.id");
Criteria query = Session.createCriteria(OtherClass.class, "oc");
query.add(Subqueries.propertyIn("oc.id", dc);
List<OtherClass> listOC = query.list();
And I was getting an error which seemed to be coming from line 2.
You can define alias and use it. Like this
DetachedCriteria dc = DetachedCriteria.forClass(Order.class, "o");
dc.createAlias("customer", "customer");
dc.add(Restrictions.lt("customer.id", 10);
dc.setProjection(Projections.property("o.id");
I have the following HQL statement:
select d.model, v.vendor from Device d, Vendor v where d.vendorId = v.id
and the following java code:
private List<Device> allDevices;
//Getter and Setter are created
public List<Device> getAllDevices() {
return allDevices;
}
public void setAllDevices(List<Device> allDevices) {
this.allDevices = allDevices;
}
public List<Device> readDevices() {
session = HibernateUtil.getSessionFactory().openSession();
String hql = "select d.model, v.vendor from Device d, Vendor v where d.vendorId = v.id";
Query query = session.createQuery(hql);
List list = query.list();
allDevices = new ArrayList();
//Here comes the code, loop, for getting the values from the list !?!
[...]
session.close();
return allDevices;
}
My Question is: How can I get the values from query.list() and add them to the allDevices ArrayList:
The class Device is a mapping class of the MySQL DB "device" table and has string column model and Integer column vendor_id. The vendor_id is the id of the "vendor" table. The "vendor" table has Integer column id and string column vendorname. I would like to show on the JSF page the model name and the corresponding vendor name instead of the vendor id.
My first attempt with the following loop is not working:
for (int i = 0; i < list.size(); i++) {
device = (Device) list.get(i);
allDevices.add(device);
}
Can anyone help me out?
I suggest using JPA instead of plain hibernate, then you can use a TypedQuery and you are using standards. Should by quite easy to make the switch and you can then drop your HibernateUtil class
#PersistenceContext
private EntityManager em;
public List<Device> readDevices() {
String hql = "select d.model, v.vendor from Device d, Vendor v where d.vendorId = v.id";
TypedQuery<Device> query = em.createQuery(hql, Device.class);
allDevices.addAll(query.getResultList());
return allDevices;
}
Also you probably don't want this code in your JSF backed bean but in a service or repository class instead.
I am new to Hibernate and I have the following piece of code in my DAO implementation class:
public Integer getEmployeeCode(String userName) {
Session session = sessionfactory.getCurrentSession();
Query q = session.createQuery("select emp.employeeCode from Employee emp where emp.userName = :username");
q.setString("username",userName);
Integer p = (Integer) q.setCacheRegion("UserNameToCode").setCacheable(true).uniqueResult();
I am using Hibernate with EhCache. I am wondering if I am using query cache correctly here? I understand that for domain objects, the query caches stores the mapping from query string and binding parameters to primary keys. However, how is the scalar values being cached in memory?
You might want to take a look at this excellent article about the 2nd level cache.
I am not quite sure, but I think you should not query for the scalar value but query the Employee by userName and return emp.getEmployeeCode() in your DAO method to take advantage of the 2nd level and query cache:
#Entity
#Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
class Employee {
#Column
Integer employeeCode;
}
public Integer getEmployeeCode(String userName) {
Session session = sessionfactory.getCurrentSession();
Query q = session.createQuery("from Employee emp where emp.userName = :username");
q.setString("username", userName);
Employee emp = q.setCacheRegion("Employee").setCacheable(true).uniqueResult();
return emp.getEmployeeCode();
}