SPRING BOOT , JAVA 11 , POSTGRES
I have a big SQL query:
select c.id,c.image_url,c.status,c.name, cat.id,cat.name
from client_organization o join organization c
on o.organization_id = c.id
join client w on o.client_id = w.id
join org_category cat on c.category_id = cat.id
where w.id = ?
So i need to convert the given result to List of Data Transfer Objects(DTO).
If it is important, here is my DTO(constructor, getters and setters are not included):
public class OrganizationListDto {
Long id;
String image;
Boolean status;
String name;
Long categoryId;
String categoryName;
}
I have been looking for solution for some days and found that this operation can be implemented in different ways(jdbc, hibernate etc)
So please explain me what and when I need to use them?
How to implement this operation?
Follow the below approach have used spingJpa
#Service
public class OrganizationServiceImpl
{
#Autowired
OrganizationListRepository organizationListRepository;
public OrganizationListDto fetch(usrId)
{
OrganizationListDto orgListData = new OrganizationListDto();
List<OrganizationListMapping> orgData = organizationListRepository.fetchData(usrId);
BeanUtils.copy(orgData,orgListData)
return orgData;
}
}
#Repository
public interface OrganizationListRepository extends JpaRepository{
#Query(native="true",value="select cat.id as id,cat.name as name
from client_organization o join organization c
on o.organization_id = c.id
join client w on o.client_id = w.id
join org_category cat on c.category_id = cat.id
where w.id = usrId"
OrganizationListMapping fetchData(#Param ("usrId") Integer usrId);
}
public interface OrganizationListMapping {
public Long getId();
public String getName();
}
public class OrganizationListDto {
Long id;
String name;
}
Related
Hi Spring and Hibernate experts!
Can any one say if it is possible to use SQL IN-clause in custom #Query in CrudRepository while the Arraylist or set of strings is passed as parameter?
I am relatively new to Spring and do not quite figure out why I get the following Spring error:
"java.lang.IllegalArgumentException: Parameter value [d9a873ed-3f15-4af5-ab1b-9486017e5611] did not match expected type [IoTlite.model.Device (n/a)]"
In this post (JPQL IN clause: Java-Arrays (or Lists, Sets...)?) the subject is discussed pretty closely but I cannot make the suggested solution to work in my case with custom #Query.
My demo repository as part of the spring boot restful application is the following:
#Repository
public interface DeviceRepository extends JpaRepository<Device, Long> {
#Query("SELECT d FROM Device d WHERE d IN (:uuid)")
List<Device> fetchUuids(#Param("uuid") Set<String> uuid);
}
And the model-class is the following:
#Entity
#SequenceGenerator(sequenceName = "device_seq", name = "device_seq_gen", allocationSize = 1)
#JsonIgnoreProperties(ignoreUnknown = true)
public class Device implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "device_seq_gen")
#JsonIgnore
private Integer id;
#Column(unique=true, length=36)
#NotNull
private String uuid = UUID.randomUUID().toString();
#Column(name="name")
private String name;
#JsonInclude(JsonInclude.Include.NON_NULL)
private String description;
#OneToMany(
mappedBy="device",
cascade = CascadeType.ALL,
orphanRemoval = true
)
private List<Sensor> sensors = new ArrayList<>();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
#JsonIgnore
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getDeviceUuid() {
return uuid;
}
public void setDeviceUuid(String deviceUuid) {
this.uuid = deviceUuid;
}
public List<Sensor> getSensors() {
return sensors;
}
public void addSensor(Sensor sensor){
sensor.setDevice(this);
sensors.add(sensor);
}
}
An here is the relevant part of the service calling the fetchUuids-custom-method with set-list of strings as parameter (service naturally being called by the relevant restcontroller):
#Service
public class DeviceService implements IDeviceService {
#Autowired
private DeviceRepository deviceRepository;
...
#Override
public List<Device> listDevices(Set<String> clientIds) {
return deviceRepository.fetchUuids(clientIds);
}
...
}
Quick fix
You have WHERE d IN (:uuid) in the custom query. You cannot match d, which is an alias for Device entity with :uuid parameter, which is a collection of Strings.
WHERE d.uuid IN (:uuid) would fix the query - it matches a String with Strings.
What you should do instead
It's rather misleading to name the method fetchUuids and return a list of Device instances. It's also unnecessary to write a custom query to do that. You can benefor from repository method name conventions and let Spring Data Jpa framework generate the query for you:
List<Device> findByUuidIn(Set<String> uuids);
You can write in this way
#Query(value = "select name from teams where name in :names", nativeQuery = true)
List<String> getNames(#Param("names") String[] names);
and call the function in service and pass an array of String as arguments.like this
String[] names = {"testing team","development team"};
List<String> teamtest = teamRepository.getNames(names);
Yes is possible to using collection in JPA query parameters.
Your query is wrong, it should be like this:
#Query("SELECT d FROM Device d WHERE d.uuid IN :uuid")
package com.mobile.model;
import javax.persistence.*;
#Entity
#Table(name = "mobile_table")
public class Mobile {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
public int mobileId;
#Column(name = "mobile_name",nullable = false,length = 20)
public String mobileName;
#Column(name = "mobile_brand",nullable = false,length = 15)
public String mobileBrand;
#Column(name="mobile_networkType")
public String mobileNetworkType;
#Column(name = "mobile_core")
public Integer mobileAvailableCore;
#Column(name = "mobile_ram")
public Integer mobileRAMSize;
#Column(name = "mobile_os")
public String mobileOS;
#Column(name = "mobile_wifif")
public Boolean mobileWifiAvailability;
#Column(name = "mobile_bluetooth")
public Boolean mobileBluethoothAvailablity;
public Mobile() {
}
public Mobile(String mobileName, String mobileBrand, String mobileNetworkType, Integer mobileAvailableCore, Integer mobileRAMSize, String mobileOS, Boolean mobileWifiAvailability, Boolean mobileBluethoothAvailablity) {
this.mobileName = mobileName;
this.mobileBrand = mobileBrand;
this.mobileNetworkType = mobileNetworkType;
this.mobileAvailableCore = mobileAvailableCore;
this.mobileRAMSize = mobileRAMSize;
this.mobileOS = mobileOS;
this.mobileWifiAvailability = mobileWifiAvailability;
this.mobileBluethoothAvailablity = mobileBluethoothAvailablity;
}
}
//Query for multiple selection
#SuppressWarnings("unchecked")
public List<Mobile> getMobileSearch(String mobileBrand, Integer mobileRAMSize, String mobileOS){
return mobileDao.findAll(Specifications.where((Specification<Mobile>) getAllMobilesByBrand(mobileBrand))
.and((Specification<Mobile>) getAllMobilesByOS(mobileOS))
.and((Specification<Mobile>) getAllMobilesByRam(mobileRAMSize)));
}
// calling function for multiple attribute Search in controller class
#RequestMapping(value="/searchMobile", method=RequestMethod.GET)
public ResponseEntity<List<Mobile>> searchMobile(#RequestParam(value="brand") String mobileBrand, #RequestParam(value="ramSize") Integer ramSize, #RequestParam(value="mobileOs") String MobileOs)
{
List<Mobile> mobileList=mobileService.getMobileSearch(mobileBrand,ramSize,MobileOs);
return new ResponseEntity<List<Mobile>>(mobileList,HttpStatus.OK);
}
// here is how my database is calling database query.
#Repository
public interface MobileDao extends CrudRepository<Mobile, Integer>, JpaSpecificationExecutor<Mobile> {
public List<Mobile> findByMobileBrand(String mobileBrand);
#Query("select distinct m.mobileBrand from Mobile m")
public List<String > getAllDistinctBrand();
public List<Mobile> findByMobileRAMSize(Integer mobileRAMSize);
#Query("select distinct m.mobileRAMSize from Mobile m")
public List<Integer> getAllDistinctRam();
public List<Mobile> findByMobileOS(String mobileOS);
#Query("select distinct m.mobileOS from Mobile m")
public List<String > getAllDistinctMobileOS();
I am trying to implement the search query for products like used in different e-commerce Websites(like Flipkart, Amazon) where user inserts different attributes for the product. Based on the product Attribute, results are shown. For the implementation i am using Spring Boot and JPA as a database.
How can i search multiple clause in single query dynamically. For Example, in case of SQL query we search multiple clause like this.
How can i implement multiple clause in JPA.
Select * from table_name where attribute1="Attb" and attribute2="Attb2" and attribute3="Attb3";
Attb, Attb2 and Attb3 are dynamically changing based on client input.
Your question was not clear enought. If you need to use variable number of conditions, you will have to use Criteria API. It allows you to conditionally create list of predicates and use that for data fetch.
http://www.objectdb.com/java/jpa/query/criteria
It will look like this:
myQueryMethod(UserChoices choices){
if(choices.someChoice1){
predicates.add(somePredicate)
}
.....
You should implement a JPA repository and use method queries :
public interface MyRepository implements JpaRepository<MODEL_CLASS, Long> {
MODEL_CLASS findAllByAtttibute1AndAttribute2AndAttribute3(String Attribute1, String Attribute2, String Attribute3);
}
I'm stuck, I run this query with hibernate, but do not know how to get the values that the query returns.
Query:
select idMagistrado, count(*) as numeroDemandas from demandamagistrado group by idMagistrado order by numeroDemandas asc limit 3;
DAO:
public Set<Magistrado> get3Magistrado() {
ConnectionDataBase cdb = new ConnectionDataBase();
Set<Magistrado> magistrados = null;
try {
Query createQuery = cdb.getSession().createQuery("select idMagistrado, count(*) as numeroDemandas from demandamagistrado group by idMagistrado order by numeroDemandas asc limit 3");
// Here, HELP!
if (magistrados == null) {
return null;
}
}
catch (HibernateException he) {
cdb.catchException(he);
}
finally {
cdb.closeSession();
}
return magistrados;
}
And the result in de MySQL console:
mysql> select idMagistrado, count(*) as numeroDemandas from demandamagistrado group by idMagistrado order by numeroDemandas asc limit 3;
+--------------+----------------+
| idMagistrado | numeroDemandas |
+--------------+----------------+
| 3 | 1 |
| 2 | 2 |
| 1 | 3 |
+--------------+----------------+
3 rows in set (0.00 sec)
The Query object has no method to let me know the values of idMagistrado and numeroDemandas. I do not know what to do, HELP.
I think you should know "HQL" is different from "SQL";
when you use HQL, you should query from class (not table).
so if you wanted excute the sql and get result in hibernate:
String sql = "select idMagistrado, count(*) as numeroDemandas from demandamagistrado
group by idMagistrado order by numeroDemandas asc limit 3";
you should use the method createSQLQuery (not createQuery) in this way:
List<Object[]> objList = cdb.getSession().createSQLQuery(sql).list();
for(Object[] objs : objList){
int idMagistrado = Integer.valueOf(objs[0]);
int numeroDemandas = Integer.valuesOf(objs[1]);
System.out.println(idMagistrado + ":" + numeroDemandas);
}
HQL is an object-oriented query language, similar to SQL, but instead of operating on tables and columns, HQL works with persistent objects and their properties.
Lets assume that we have a database table structure like below :
Then the Entity class for each table can be given (Hibernate mapping Java classes to database tables):
Subject
public class Subject implements java.io.Serializable {
private Integer id;
private String subName;
private String day;
private String time;
private Set subjectHasStuDetailses = new HashSet();
public Subject() {
}
//getters and setters
...
StuDetails
public class StuDetails implements java.io.Serializable {
private Integer id;
private String FName;
private String LName;
private String sex;
private String dob;
private Set subjectHasStuDetailses = new HashSet();
public StuDetails() {
}
//getters and setters
...
SubjectHasStuDetails
public class SubjectHasStuDetails implements java.io.Serializable {
private Integer id;
private StuDetails stuDetails;
private Subject subject;
public SubjectHasStuDetails() {
}
//getters and setters
...
In every entity class we can override the default constructor as we need.
Lets assume that our entity classes are in a package named com.hibernate.entities. If we need to get all the subjects doing by a selected student then our Hql query can be:
Query query = ss.createQuery("FROM com.hibernate.entities.SubjectHasStuDetails shs WHERE "
+ "shs.stuDetails.id= :s_id").
setInteger("s_id", 32);
List<com.hibernate.entities.SubjectHasStuDetails> shs = query.list();
for (SubjectHasStuDetails sh : shs) {
sh.getSubject().getSubName();
}
As we can see in the given example of Hql query we are referring to entity members of the class which is mapped to the required table.Not referring the table column names.
So in your case also you should refer the mapped entities.
SELECT d.member_variable, COUNT(*) AS d.member_variable FROM packagename.EntitityClass d GROUP BY d.member_variable ORDER BY d.member_variable ASC LIMIT 3
Update:
If you are using identified relationship:
Subject:
public class Subject implements java.io.Serializable {
private Integer id;
private String subName;
private String day;
private String time;
private Set<Student> students = new HashSet<>();
...
Student:
public class Student implements java.io.Serializable {
private Integer id;
private String FName;
private String LName;
private int age;
private Set subjects = new HashSet();
...
Query:
Query q = s.createQuery("FROM com.hibernate.entities.Subject sub JOIN sub.students s WHERE s.id= :stu_id")
.setInteger("stu_id", 1);
List<String> subj = q.list();
for (String ss : subj) {
System.out.println(ss);
}
i'm on a final project now and making web app using hibernate.
my topic is recipe web site, and i have to show all the likers for a recipe
here's my pojo class for likes (not including the constructor and getter setter here to make it short code)
public class Likes implements java.io.Serializable {
private LikesId id;
private Member member;
private Resep resep;
private Integer likes;
public Likes() {
}
}
here's my pojo class for likes id (not including the getter setter here to make it short code)
public class LikesId implements java.io.Serializable {
private String idResep;
private String idMember;
public LikesId() {
}
public LikesId(String idResep, String idMember) {
this.idResep = idResep;
this.idMember = idMember;
}
}
now here is my method to show all likers for a recipe
public ArrayList<Likes> getAllLikes(String kode_resep)
{
this.session = NewHibernateUtil.getSessionFactory().openSession();
ArrayList<Likes> hasil = null;;
Transaction tx = session.beginTransaction();
Query q = session.createQuery("from Likes join LikesID on ()='"+kode_resep+"'");
hasil = (ArrayList<Likes>) q.list();
session.close();
return hasil;
}
the error when i run this method is:
Exception in thread "main"
org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected AST
node: ( near line 1, column 35 [from model.Likes where
Likes.getId().getIdResep()='R001']
Try this:
Query q = session.createQuery("from Likes l where l.id.idResep = :code_resep");
q.setParameter("code_resep",kode_resep);
q.list();
The following JPA query doesn't compile:
#NamedQuery(name = "PSA.findBySourceSystem",
query = "SELECT p FROM PSA p WHERE p.sourceSystem.id = :sourceSystemId")
p.sourceSystem is the following enum:
public enum SourceSystem {
FIRST(3, "ABC"), SECOND(9, "DEF"), THIRD(17, "GHI");
private int id;
private String code;
...
}
and is mapped in PSA's base class:
public class PsaBase implements Serializable {
#Column(name = "sourceSystemId")
#Enumerated(EnumType.ORDINAL)
protected SourceSystem sourceSystem;
...
}
The query compiles and runs fine if I replace p.sourceSystem.id in the query with something more benign.
Thank you in advance for any help.
It shouldn't compile.
You have to resolve the required enum value manually before passing it as a query parameter:
#NamedQuery(name = "PSA.findBySourceSystem",
query = "SELECT p FROM PSA p WHERE p.sourceSystem = :sourceSystem")
.
public enum SourceSystem {
...
private static Map<Integer, SourceSystem> valuesById = new HashMap<Integer, SourceSystem>();
static {
for (SourceSystem s: values())
valuesById.put(s.id, s);
}
public static SourceSystem findById(int id) {
return valuesById.get(id);
}
}
.
em.createNamedQuery("PSA.findBySourceSystem")
.setParameter("sourceSystem", SourceSystem.findById(sourceSystemId));
EDIT:
Since sourceSystem is annotated as #Enumerated(EnumType.ORDINAL), it's stored in the database as the ordinal numbers of the corresponding enum values, therefore FIRST is stored as 0. JPA doesn't directly support using arbitrary field of the enum value to identify it in the database. If your database schema assumes so, you can do the following trick to decouple state of your object from the database schema:
public class PsaBase implements Serializable {
protected SourceSystem sourceSystem;
#Column(name = "sourceSystemId")
public Integer getSourceSystemId() {
return sourceSystem.getId();
}
public void setSourceSystemId(Integer id) {
this.sourceSystem = SourceSystem.findById(id);
}
... getter and setter of sourceSystem with #Transient ...
}