I have such a two classes:
public class Average {
long id;
String name;
double average;
public Average(long id , String name , double payment)
{
this.id = id;
this.name = name;
this.payment = payment;
}
#Override
public String toString()
{
return id + "\t" + name + " " + payment;
}
}
and
#Entity
public class Payment{
#Id
#GeneratedValue
long id;
Student student;
Subject subject;
double payment;
public Payment()
{
}
and I want to perform query on this class with java, but it is not working correctly. What can be wrong. Bellow I posted my query from another class where I call it:
public List<Object> getPayment()
{
Query q = entityManager.createQuery("Select NEW Average( g.subject.id , g.subject.name , AVG(g.payment) ) from Payment g GROUP BY g.subject.id, gge.subject.name");
return q.getResultList();
}
Please be patient with me, this is my first post!
Average is not an entity (you should annotate it with #Entity - like the one you did for Payment) so you cannot perform entityManager.createQuery().
Also you should specify table #Table(name = "XXX") after #Entity and before class name.
Query should be something like:
Select g.subject.id , g.subject.name , AVG(g.payment) from Average a, Payment g GROUP BY g.subject.id, g.subject.name
-- UPDATE
If Average is a Bean class used for projection then do the following:
Object[] payments = (Object[]) entityManager.createQuery("Select g.subject.id,
g.subject.name, AVG(g.payment) from Payment g
GROUP BY g.subject.id, g.subject.name").getSingleResult();
then iterative through the objects of payments:
for (Object object : payments) {
System.out.println(object);
}
if the result is just one row then put getSingleResult otherwise you need a List of the objects and iterate through the list:
List<Object[]> payments = (List<Object[]>) entityManager.createQuery("Select g.subject.id,
g.subject.name, AVG(g.payment) from Payment g
GROUP BY g.subject.id, g.subject.name").getResultList();
then iterative through the objects of payments:
if (payments != null){
for (Object[] object : payments) {
System.out.println(object[0] + " " + object[1] + " " + object[2]);
}
}
Could it be the gge instead of g in GROUP BY g.subject.id, gge.subject.name?
Related
I am trying to get count from a postgreSQL database using Spring Data JPA createNativeQuery. However, the query is returning null instead of the actual values.
Here is the JPA createNativeQuery statement below:
Query q = entityManager.createNativeQuery("SELECT null AS id,
count(case when (IS_QUERIED = false AND SUBMITTED = true)
then 1 else null end) AS pending,
count(case when ( (SUBMITTED = true)) then 1 else null end) AS submitted,
count(*) AS totalApplications FROM ANNUAL_RETURNS ", AnnualReturn.class);
//Note: AnnualReturn is the name of the #Entity class
List <AnnualReturn> countList=q.getResultList();
return countList;
I need help mapping the "submitted", "pending" and "totalApplications" instances from my query in a way that returns the result as below.
Result expected is:
"data": {
"totalApplications": 2000,
"submitted": 560,
"pending": 60,
}
Result am getting:
{
"data": [
null
]
I would appreciate any help.
I do not know why but I believe SELECT null AS id is causing null record to be fetched.
If you don't want id to be fetched then you can use projection with custom RowMapper or DTO projection.
See below:
#Entity
#Data
#ToString
class A {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
Long id;
String name;
int age;
public A() {
}
public A(String name, int age) {
this.name = name;
this.age = age;
}
}
interface ARepo extends JpaRepositoryImplementation<A, Long> {
}
#Component
#RequiredArgsConstructor
class Init {
final ARepo repo;
final EntityManager em;
#EventListener
public void init(ContextRefreshedEvent evt) {
repo.save(new A("XX", 5));
repo.save(new A("ZZ", 6));
repo.save(new A("AA", 11));
repo.save(new A("AB", 12));
Query q = em.createNativeQuery("select 0 as id, a.name as name, a.age as age from A a where a.total > 10 ", A.class);
System.out.println(q.getResultList()); //fetches AA and BB
//if you change the query to select null as id it would return [ null, null]
}
}
You shouldn't use a typed Query here, try something like
Query q = entityManager.createNativeQuery("SELECT " +
" COALESCE(sum(case when (IS_QUERIED = false AND SUBMITTED = true) " +
" then AMOUNT else 0 end),0) AS pending, " +
" COALESCE(sum(case when ( (SUBMITTED = true)) then 1 else 0 end),0) AS submitted, " +
" COALESCE(sum(AMOUNT),0) AS totalApplications FROM ANNUAL_RETURNS ");
List <Object[]> countList=q.getResultList();
Object[] obj = countList.get(0);
for (Object value : obj) {
System.out.println(value);
}
long pending = ((BigInteger)obj[0]).longValue();
long submitted = ((BigInteger)obj[1]).longValue();
long total = ((BigInteger)obj[2]).longValue();
return ...; // prepare the values to your convinience
EDIT
changed null to 0 to avoid possible null values in the result
EDIT
fixed NPE on empty table
This is not classical N+1 problem. My issue is conserning using projections and DTO objects in Jpa.
I have next method with JPA Query:
public List<MeterDTO> getAllBrokenMeterByHouseServ(House house, Serv serv, Date dt) {
Query query =em.createQuery("select new MeterDTO(m, g.kart.lsk, nvl(e.tp,0)) from Meter m "
+ "join m.exs e with m.id=e.meter.id "
+ "join m.meterLog g with m.meterLog.id=g.id "
+ "join g.kart k with g.kart.id=k.id and :dt between k.dt1 and k.dt2 "
+ "join g.serv s with g.serv.id=s.id "
+ "join k.kw kw with k.kw.id=kw.id "
+ "join kw.house h with kw.house.id=h.id "
+ "where s.id = :servId "
+ "and kw.house.id = :houseId "
+ "and :dt between e.dt1 and e.dt2 and nvl(e.tp,0) in (2,3,4) "
+ "");
query.setParameter("servId", serv.getId());
query.setParameter("houseId", house.getId());
query.setParameter("dt", dt);
return query.getResultList();
}
I fetch records from the query above into
data transfer object:
meterDao.getAllBrokenMeterByHouseServ(house, serv, dt2).stream().forEach(t-> {
log.info("meter.id={}, lsk={}, tp={} ", t.getMeter().getId(), t.getLsk(), t.getTp());
});
MeterDTO:
#Getter #Setter
public class MeterDTO {
private Meter meter;
private Integer lsk;
private Double tp;
public MeterDTO(Meter meter, Integer lsk, Double tp) {
super();
this.meter = meter;
this.lsk = lsk;
this.tp = tp;
}
}
Why does hibernate produce one main query:
select
meter0_.ID as col_0_0_,
kart3_.lsk as col_1_0_,
nvl(exs1_.TP,
0) as col_2_0_
from
MT.METER meter0_
inner join
MT.METER_EXS exs1_
on meter0_.ID=exs1_.FK_METER
and (
meter0_.ID=exs1_.FK_METER
)
inner join
MT.METER_LOG meterlog2_
on meter0_.FK_METER_LOG=meterlog2_.ID
and (
meter0_.FK_METER_LOG=meterlog2_.ID
)
inner join
AR.KART kart3_
on meterlog2_.FK_KLSK_OBJ=kart3_.FK_KLSK_OBJ
and (
kart3_.lsk=kart3_.lsk
and (
? between kart3_.DT1 and kart3_.DT2
)
)
inner join
AR.KW kw6_
on kart3_.FK_KW=kw6_.ID
and (
kart3_.FK_KW=kw6_.ID
)
inner join
AR.HOUSE house7_
on kw6_.FK_HOUSE=house7_.ID
and (
kw6_.FK_HOUSE=house7_.ID
)
inner join
TR.SERV serv5_
on meterlog2_.FK_SERV=serv5_.ID
and (
meterlog2_.FK_SERV=serv5_.ID
)
where
serv5_.ID=?
and kw6_.FK_HOUSE=?
and (
? between exs1_.DT1 and exs1_.DT2
)
and (
nvl(exs1_.TP, 0) in (
2 , 3 , 4
)
)
and multiple queries with different bind argument "?" to load every entity:
select
meter0_.ID as ID1_44_0_,
meter0_.FK_K_LSK as FK_K_LSK2_44_0_,
meter0_.FK_METER_LOG as FK_METER_LOG4_44_0_,
meter0_.TRANS_RATIO as TRANS_RATIO3_44_0_
from
MT.METER meter0_
where
meter0_.ID=?
How to avoid this issue? I want to load all entities Meter in one main query.
Is it possible?
I use:
<spring-framework.version>5.0.5.RELEASE</spring-framework.version>
<hibernate.version>5.1.0.Final</hibernate.version>
Any help would be greatly appreciated.
upd1
I simplified my JPA query code to this:
public List<MeterDTO> getAllBrokenMeterByHouseServ(House house, Serv serv, Date dt) {
Query query =em.createQuery("select new com.ric.bill.dto.MeterDTO(m) from Meter m ");
}
But it still produces mutiple queries:
select
meter0_.ID as ID1_44_0_,
meter0_.FK_K_LSK as FK_K_LSK2_44_0_,
meter0_.FK_METER_LOG as FK_METER_LOG4_44_0_,
meter0_.TRANS_RATIO as TRANS_RATIO3_44_0_
from
MT.METER meter0_
where
meter0_.ID=?
20-04-2018 12:52:49.482 [main] DEBUG o.h.l.p.e.p.i.ResultSetProcessorImpl - Starting ResultSet row #0
20-04-2018 12:52:49.482 [main] DEBUG org.hibernate.SQL -
select
meter0_.ID as ID1_44_0_,
meter0_.FK_K_LSK as FK_K_LSK2_44_0_,
meter0_.FK_METER_LOG as FK_METER_LOG4_44_0_,
meter0_.TRANS_RATIO as TRANS_RATIO3_44_0_
from
MT.METER meter0_
where
meter0_.ID=?
<Skipped>
very strange!
upd2 Meter entity:
#SuppressWarnings("serial")
#Entity
#Table(name = "METER", schema="MT")
#Getter #Setter
public class Meter extends Base implements java.io.Serializable, Storable {
public Meter (){
}
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "ID", updatable = false, nullable = false)
protected Integer id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="FK_METER_LOG", referencedColumnName="ID")
private MeterLog meterLog ;
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval=true)
#JoinColumn(name="FK_METER", referencedColumnName="ID")
#BatchSize(size = 50)
private List<Vol> vol = new ArrayList<Vol>(0);
#OneToMany(fetch = FetchType.LAZY)
#JoinColumn(name="FK_METER", referencedColumnName="ID")
#BatchSize(size = 50)
private List<MeterExs> exs = new ArrayList<MeterExs>(0);
#Column(name = "TRANS_RATIO", updatable = true, nullable = true)
private Double trRatio;
}
In DTO you have 'Meter meter' field, in meter field you have 'MeterLog meterlog' etc. In this case Hibernate is additionally loading for field for full object. This DTO is to much complex. Try to create more flat object:
public class MeterDTO {
private Integer meterId
private Double meterTrRatio
private Integer lsk;
private Double tp;
(...)
And query will be:
(...) new MeterDTO(m.id, m.trans_ratio, g.kart.lsk (...)
And after that you can extending your DTO for the next fields you want.
The accepted answer suggests changing the DTO, which would not always an acceptable solution.
Here is a solution with no need to change your DTO.
Write your HQL like this:
from Meter m
join m.exs e with m.id=e.meter.id
join m.meterLog g with m.meterLog.id=g.id
join g.kart k with g.kart.id=k.id and :dt between k.dt1 and k.dt2 "
join g.serv s with g.serv.id=s.id "
join k.kw kw with k.kw.id=kw.id "
join kw.house h with kw.house.id=h.id "
(more joins and wheres)
Note that there should not be any select.
getResultList will give you List<Object[]>. Each entry is an array of {Meter, m.exs, m.meterLog, g.kart, ....}. Pick the ones you need and make your MeterDTO.
In my case:
jpa repo
#Query("from Bind bind "
+ "left join Employee employee "
+ "with bind.empCode = employee.empCode "
+ "where bind.accountName = :hiveAccount and bind.disabled = 1 ")
List<Object[]> listMembers(#Param("hiveAccount") String hiveAccount);
DTO
public class BindDTO {
Bind bind;
Employee emp;
public BindDTO(Object[] objs) {
this((Bind) objs[0], (Employee) objs[1]);
}
service
myRepo.listMembers(hiveAccount).stream().map(BindDTO::new).collect(Collectors.toList());
select a.empname,b.dname from employee a, department b where a.deptid=b.deptid
Employee table contains empid,empname & deptid
Department tables contains deptid & dname
There is some change in hql join.
For hql join we use classess insted of tables
if you have classes Employee and Department.
You can use query like
select a.empname,b.dname from Employee as a
left outer join Employee.department as b
where empname, dname and department are fields of Employee,Department and Employee class.
Above query will return List you have to handle it properly.
Then convert this list to json object
I hope this helps. You need a DTO to store the data and send it as JSON to frontend.
#Query("new com.example.service.model.search.SearchDTO"
+"(e.empname, d.dname) "
+ "from department d "
+ "join d.deptid e "
+ "where e.id=?1")
public List<SearchDTO> findByIdEmployee (Long idEmployee );
Possible DTO structure:
public class SearchDTO {
String EnpName;
String DepName;
public SearchDTO(String EnpName, String DepName) {
this.EnpName = EnpName;
this.DepName = DepName;
}
public String getEnpName() {
return EnpName;
}
public void setEnpName(String EnpName) {
this.EnpName = EnpName;
}
public String getDepName() {
return DepName;
}
public void setDepName(String DepName) {
this.DepName = DepName;
}
}
There are three ways to do,
HQL
One to One mapping.
Native Query using hibernate.
Best to Use : One to One mapping.
Refer : https://github.com/Roshanmutha/hibernate-samples/blob/master/R6_One_To_One_Mapping/src/main/java/entity/User.java
Is there any way to get this query with QueryDSL?
select
person.name,
count(neighbors.*)
from person as neighbors
where person.address = neighbor.address
group by person.name
where address is not a FK.
The key to the first problem is to use aliases to be able to make the self-join:
// static instance uses default alias "person"
QPerson person = QPerson.person;
QPerson neighbor = new QPerson("neighbor");
JPAQuery query = new JPAQuery(em)
.from(person, neighbor)
.where(person.adress.eq(neighbor.adress))
.groupBy(person.name);
To get the results you can simply use the Tuple class:
List<Tuple> results = query.list(person.name, neighbor.count());
for (Tuple row : result) {
System.out.println("name: " + row.get(person.name));
System.out.println("count: " + row.get(neighbor.count()));
}
Or you can use a ConstructorExpression to do something like this:
List<MyResult> results = query.list(ConstructorExpression.create(
MyResult.class, person.name, neighbor.count()));
public class MyResult {
private String name;
private long count;
public MyResult(String name, long count) {
this.name = name;
this.count = count;
}
}
I get a ClassCastException when trying to query my JPA entity class. I only want json to show two columns. That is name and address. How do I only show selected columns in JPA? From debugging it has to be the for loop. So List is the object and I need to make the right side an object instead of a list correct?
Entity
#Entity
#Table(name = "Personnel")
public class User implements Serializable {
private String id;
private String name;
private String address;
public User(String id, String name, String address)
{
this.id = id;
this.name = name;
this.address = address;
}
#Id
#Column(name = "name", unique = true, nullable = false)
public String getName() {
return this.name;
}....
//setters getters
Query/Impl
public List<User> getRecords(User ent){
String sql = "select "
+ " usr.name, usr.address "
+ " from User usr"
+ " where usr.id = '1' ";
List<User> records = this.getSession().createQuery(sql).list();
for ( User event : records ) {
System.out.println( "Records (" + event.getName + ") );
}
return records;
}
Update
This is my attempt to declare the result object as List. Does the method have to be an object instead of ?
public List<User> getRecords(User ent){
String sql = "select "
+ " usr.name, usr.address "
+ " from User usr"
+ " where usr.id = '1' ";
Map<String, String> results = new HashMap<String, String>();
List<Object[]> resultList = this.getSession().createQuery(sql).list();
// Place results in map
for (Object[] items: resultList) {
results.put((String)items[0], (String)items[1]);
results.toString();
}
return (List<User>) results;
You can pass a DTO class to the SELECT clause like this:
List<UserDTO> resultList = this.getSession().createQuery("""
select
new my.package.UserDTO(usr.name, usr.address)
from User usr
where usr.id = :userId
""")
.setParameter("userId", userId)
.getResultList();
You should read the complete object:
String sql = " from User usr"
+ " where usr.id = '1' ";
Or declare the result object as List<Object[]>
You can use generic(I assure you are using java 1.5 and above) and and one you get result, you do type check and downcast to desired type.
If You don't want to read the complete object you have to use Criteria and Projection on specific properties.
See this answer it will help