I have a fields of customerName, MembershipNumber, nationality and some other field in my customer table and if i get one value from the above three. I need to write only one named query to get the value from the Customer table from the value i got. Is there any possibility to do that by named query without use of normal query in jpa?...
StringBuilder s=new StringBuilder();
s.append("select c from customerdetail c where )
if(customerName!=null)
{
s.append(" c.customerName = :customerName")
}
else if(memberShipNumber!=null)
{
s.append(" c.memberShipNumber = :memberShipNumber")
}
else if(nationality!=null)
{
s.append(" nationality = :nationality)
}
Here i use the same table with three conditions. So is there any possiblity to write only one named query or any other static query to satisfy all the three conditions in jpa?
Try reading ObjectDB's manual on JPA Queries. It provides information on selecting JPA entities and different variations with its custom fields. It has query examples expressed as in JPQL so with use of Criteria. And yes, you can define namedQuery using JPQL and later use-re-use it.
Named queries are static & their scope is persistence context, they can't be altered at runtime.
Below is the sample for adding parameter based on condition using Criteria API.
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<CustomerDetail> cq = cb.createQuery(CustomerDetail.class);
Metamodel m = em.getMetamodel();
EntityType<CustomerDetail> CustomerDetail_ = m.entity(CustomerDetail.class);
Root<CustomerDetail> detail = cq.from(CustomerDetail.class);
if(customerName != null)
cq.where(cb.equal(detail.get(CustomerDetail_.customerName), customerName));
if(memberShipNumber != null)
cq.where(cb.equal(detail.get(CustomerDetail_.memberShipNumber), memberShipNumber));
if(nationality != null)
cq.where(cb.equal(detail.get(CustomerDetail_.nationality), nationality));
cq.select(detail);
TypedQuery<CustomerDetail> q = em.createQuery(cq);
List<CustomerDetail> customerList= q.getResultList();
Else, you can go with building a query with string by appending conditions, instead of named query.
You can use projection with NamedQuery, this example will obtain a single customerName field if MembershipNumber is unique or a List with every customerName that matches the where condition:
#Entity
#NamedQuery(name="getCustomerName", query="SELECT c.customerName FROM Customer c WHERE c.membershipNumber = :memNum")
public class Customer {
...
}
Then you can call it with: (em is your EntityManager)
String customerName = em.createNamedQuery("getCustomerName")
.setParameter("memNum", myMembershipNumber)
.getSingleResult();
Related
The scenario is:
Entity Student
ID
Name
List Courses
Entity Course
ID
Name
Student
Now I need the list of students who are studying course 'Programming'
How can I achieve this using Criteria Query.
try this:
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Student> cq = cb.createQuery(Student.class);
Root<Student> rootStudent = cq.from(Student.class);
Join<Student,Course> joinCourse = rootStudent.join("courses",JoinType.INNER);
cq.where(cb.equals(joinCourse.get("Name"),"Proggraming"));
cq.select(rootStudent);
List<Student> res = entityManager.createQuery(cq).getResultList();
In this example I assume that you have the JPA entities well modeled, including bidirectional relationships. It would also be recommended if it is for an API that you use pojos instead of returning a JPA entity to the web part, for this you should use multiselect instead of select and specify each of the fields you want to obtain, but as a first approximation it would be valid.
It would also be advisable to use metamodels for JPA entities instead of accessing the properties through a string with the name (join, get methods ..)
In this scenario, it does not make sense to make a subquery, I change the query to find the students of the courses Proggraming1 or Proggraming2 through a subquery(I would still prefer to do it by filtering the joins without using subquery), it would be something like this:
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Student> cq = cb.createQuery(Student.class);
Root<Student> rootStudent = cq.from(Student.class);
Join<Student,Course> joinCourse = rootStudent.join("courses",JoinType.INNER);
Subquery<Long> subqueryIdCourse = cq.subquery(Long.class);
Root<Course> rootCourseSq = subqueryIdCourse.from(Course.class);
subqueryIdCourse.where(
cb.or(
cb.equals(rootCourseSq.get("Name"),"Proggraming1"),
cb.equals(rootCourseSq.get("Name"),"Proggraming2")))
subqueryIdCourse.select(rootCourseSq.get("ID"))
cq.where(joinCourse.get("ID").in(subqueryIdCourse.getSelection()));
cq.select(rootStudent);
List<Student> res = entityManager.createQuery(cq).getResultList();
Let's say, I have a query like
Select a.valA, b.valB
from tableA a join tableB b on a.joinCol = b.joinCol
where a.someCol = 1.
I want to execute it using Hibernate (and Spring Data) in one query to the database. I know, I can write just
Query query = em.createQuery(...);
List<Object[]> resultRows = (List<Object[]>)query.getResultList();
But my question would be - is it possible to do it in a typesafe way, using CriteriaQuery for example? The difficulty is, that, as you see, I need to select values from different tables. Is there some way to do this?
Simple example where an Employee has many to many relation to several jobs that he may have :
CriteriaBuilder builder = session.getCriteriaBuilder();
CriteriaQuery<Tuple> criteria = builder.createTupleQuery();
Root<TableA> root = criteria.from(TableA.class);
Path<Long> qId = root.get("id");
Path<String> qTitle = root.get("title");
Join<TableA, TableB> tableTwo = root.join("joinColmn", JoinType.INNER);
criteria.multiselect(qId, qTitle, tableTwo);
List<Tuple> tuples = session.createQuery(criteria).getResultList();
for (Tuple tuple : tuples)
{
Long id = tuple.get(qId);
String title = tuple.get(qTitle);
TableB tableB= tuple.get(tableTwo);
}
but saw that there is an alternate answer here :
JPA Criteria API - How to add JOIN clause (as general sentence as possible)
I've a database with many thousands of tables that have been (and continue to be) created with a naming strategy - one table per calendar day:
data_2010_01_01
data_2010_01_02
...
data_2020_01_01
All tables contain sensor data from the same system in the same shape. So a single entity (lets call it SensorRecord) will absolutely map to all tables.
I'd imagined something like this would work:
#Query(nativeQuery = true, value = "SELECT * FROM \"?1\"")
Collection<SensorRecord> findSensorDataForDate(String tableName);
But it does not, and reading around the topic seems to suggest I am on the wrong path. Most posts on dynamic naming seem to state explicitly that you need one entity per table, but generating thousands of duplicate entities also seems wrong.
How can I use JPA (JPQL?) to work with this data where the table name follows a naming convention and can be changed as part of the query?
Parameters are only allowed in the where clause.
You can create custom repository method returns collection of SensorRecord dto. No need to map so many entities. You should get List<Object []> as query result and manually create dto objects.
#Autowired
EntityManager entityManager;
public List<SensorRecord> findSensorDataForDate(LocalDate date) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy_MM_dd");
String tableName = "data_" + date.format(formatter);
Query query = entityManager.createNativeQuery(
"select t.first_column, t.second_column from " + tableName + " t");
List<Object[]> queryResults = query.getResultList();
List<SensorRecord> sensorRecords = new ArrayList<>();
for (Object[] row : queryResults) {
SensorRecord record = new SensorRecord();
record.setFirstParameter((Integer) row[0]);
record.setSecondParameter((String) row[1]);
sensorRecords.add(record);
}
return sensorRecords;
}
Could it be just syntax error?
This has worked for me:
#Query(value = "select * from job where job.locked = 1 and job.user = ?1", nativeQuery = true)
public List<JobDAO> getJobsForUser(#Param("user") String user);
I have a mysql database with employee information, each employee has a technical id as primary key. In MySQL to selcet row(s) matching criteria, i can just use to get the following statement (works)
SELECT * FROM database_test.employee WHERE fist_name='First1';
In Java i can also use this as a native statement to get what i want (works):
List<EmployeeEntity2> objects = m_em.createNativeQuery(
"SELECT * database_test.employee WHERE first_name='First1'",
EmployeeEntity2.class).getResultList();
However, i wanted to use the Criteriabuilder to get the same result and later generalize it for multiple columnName=columnEntry selections.
public List<EmployeeEntity2> testNoParameter() {
//Based on https://www.objectdb.com/java/jpa/query/criteria
CriteriaBuilder cb = m_em.getCriteriaBuilder();
CriteriaQuery<EmployeeEntity2> q = cb.createQuery(EmployeeEntity2.class);
Root<EmployeeEntity2> c = q.from(EmployeeEntity2.class);
ParameterExpression<String> p = cb.parameter(String.class);
//Works
//q.select(c).where(cb.equal(c.get("firstName"), p));
//Won't work
q.select(c).where(cb.equal(c.get("first_name"), p));
TypedQuery<EmployeeEntity2> query = m_em.createQuery(q);
query.setParameter(p, "First1");
List<EmployeeEntity2> results = query.getResultList();
return results;
}
Using "fist_name" - the column name annotation from the Entity - will yield the following java.lang.IllegalArgumentException with:
Unable to locate Attribute with the the given name [first_name] on this ManagedType [xx.xxx.database.EmployeeEntity2]
EmployeeEntity2 has "fist_name" annotation:
#Column(name = "first_name", nullable = false)
#Override
public String getFirstName() {
return super.getFirstName();
}
So "first_name" should exist, however (with some debugging) i found out that the attribute expected is for some reason "firstName" instead - which i have not defined/annotated - so where does it come from - and how can i use the column names actually defined in the database (column = "first_name")?
You should use property name of entity (not column name) to use it in criteria builder so instead of
q.select(c).where(cb.equal(c.get("first_name"), p));
use
q.select(c).where(cb.equal(c.get("firstName"), p));
CriteriaBuilder is RDBMS schema agnostic, so you use your model (entities), not schema (table names etc).
In JPA you dont normally use SQL but JPQL. Equivalent of your SQL in JPQL would be something like
"SELECT e FROM EmployeEntity2 e WHERE e.firstName='First1'"
Both CriteriaQuery tree and JPQL string are transformed down to the same query tree later on (can't remember the name), so they both must comply to the very same rules.
when i run my query in database visualizer its working perfectly, but i think there are some issues in syntax when i convert it in my DAO class method.
I want to get whole data against the name provided
In Visualizer:
SELECT first_name,last_name,nic,phone,email FROM x_hr_user where (first_name = 'Irum');
Now in Dao
public List<XHrUser> findXHrUserByNameInTable()
{
String name ="Irum";
Query query = em.createQuery("SELECT xHrNewUserObj.firstName,xHrNewUserObj.lastName, xHrNewUserObj.nic, xHrNewUserObj.phone, xHrNewUserObj.emil FROM XHrUser xHrNewUserObj where (xHrNewUserObj.firstName) = (name)");
List<XHrUser> list = query.getResultList();
return list;
}
Instead of showing single row, it displays whole data Table
Thank you
Your current query is not valid JPQL. It appears that you intended to insert the raw name string into your query, which could be done via a native query, but certainly is not desirable. Instead, use a named parameter in your JPQL query and then bind name to it.
String name = "Irum";
Query query = em.createQuery("SELECT x FROM XHrUser WHERE x.firstName = :name")
.setParameter("name", name);
List<XhrUser> list = query.getResultList();
You have to write query as below. where : is used for variable
Query query = em.createQuery("SELECT xHrNewUserObj.firstName,xHrNewUserObj.lastName, xHrNewUserObj.nic, xHrNewUserObj.phone, xHrNewUserObj.emil FROM XHrUser xHrNewUserObj where (xHrNewUserObj.firstName) = :name");