I want to save the result of a query on a List. But when I debug to see the list, it's full of Object[], not a Conta class.
Here is my query and the Conta class.
Query query = em.createQuery("SELECT p.data data, c.nome nomePedido, c.valor, g.nome nomeGarcom FROM Pedidos p\n"
+ " JOIN Cardapio c ON p.idItem = c.id\n"
+ " JOIN Garcons g ON p.idGarcon = g.id", Conta.class);
contaList = query.getResultList();
public class Conta {
private Date data;
private String nomeGarcom;
private String nomePedido;
private float valor;
public Conta(Date data, String nomePedido, float valor, String nomeGarcom) {
this.data = data;
this.nomeGarcom = nomeGarcom;
this.nomePedido = nomePedido;
this.valor = valor;
} ... getters and setters
AFAIK, you can use a constructor expression in JPA, especially since already have a matching constructor:
Query query = em.createQuery("SELECT new com.mine.Conta(p.data, g.nome, c.nome, c.valor) FROM Pedidos p\n" ...
Your Conta class is no Jpa #Entity - that's why it doesn't know how to map the result to your Java Class. Annotate Conta properly, give it a primary key, that's the most straight-forward way.
#Entity
public class Conta {
#Id
private long someID;
#Column
private float valor;
#Column
... more columns (watch out for your Timestamp, probably needs #Temporal)
....getters and setters
}
As is, you can't use Jpa to save instances of your Conta into the database which is probably one thing you're looking to do later.
Consider this Answer too: JPA : How to convert a native query result set to POJO class collection
Leandro, can you also please attach the code of getResultList()? From my experience, there are two potential causes. One, your getResultList method has the wrong return type. Two, your query is not working at all.
Related
Let's say I have a query like this:
Query object
public class myObject {
private String code;
private String name;
}
query method
#Query(nativeQuery = true,value = "...")
findByAcodeAndBname(List<MyObject> queryObject);
Pseudocode of the query
select a.code, b.name from tableA a
left join table b on a.column = b.column
where a.code = ${} b.name = ${}
Since it could cause performance issues just simply using foreach code in Java to do the query, how do I map every pair of a.code and b.name using native JPA query like mybatis foreach tag? Or is it posssible?
I think you don't need native query here, because the costs of querying data from the database and transfering it over network are higher than any related Java operations.
Instead of native query you can use JPQL query, e.g.
#Query("select new com.tsypanov.domain.HasIdAndNameDto(e.id, e.name)" +
" from ManyFieldsEntity e " +
"where e.name = :name")
List<HasIdAndName> findAllByNameUsingDto(#Param("name") String name);
Here we call constructor of DTO from JPQL query passing the fields from our entity. The DTO class must have the specified constructor:
#RequiredArgsConstructor
public class HasIdAndNameDto {
private final Long id;
private final String name;
}
Suppose I have the following JPA entity:
#Entity
#Table(name = "places")
public class Place {
#Id #GeneratedValue
private Long id;
private String name;
private double lat;
private double lng;
// Getters and setters
}
And a Spring repository called PlacesRepository which have a native query:
public interface PlacesRepository extends CrudRepository<Place, Long> {
#Query(
value = "SELECT *, DISTANCE(lat,lng,:myLat,:myLng) AS distance " +
"FROM places ORDER BY distance",
nativeQuery = true
)
List<Place> nearestPlaces(
#Param("myLat") double myLat,
#Param("myLng") double myLng
);
}
That DISTANCE function is just to exemplify a native database function. Since I'm using PostGIS, it would be equivalent to ST_Distance. It returns the distance using the coordinates of each record and those of the method.
How do I capture that "distance" field without having to store it in the table??? I don't want to store it because it is dynamic. I just want to return it with the entity as a json.
An option here is to use HQL, not a native query. For example, you can create a simple result class:
class PlaceToDistancePair {
private Place place;
private double distance;
public PlaceToDistancePair(Place place, double distance) {
this.place = place;
this.distance = distance;
}
// getters and setters
}
and then your #Query will look somehow like this:
#Query(
value = "SELECT new PlaceToDistancePair(p, DISTANCE(lat,lng,:myLat,:myLng)) FROM places p")
List<PlaceToDistancePair> placeToDistanceList;
You can find more about select new here and also there you will find select new map construction, which maybe can also be suitable for you to map Place to distance without PlaceToDistancePair class.
However, in case your function (e.g. ST_Distance) is not registered in the hibernate dialect, you need to register it yourself. Check here how Vlad does this in the "Registering the SQL function with the Hibernate Dialect" section.
Also an option for you is to use CriteriaBuilder API, which is much more flexible, but requires more code. Read here for more
Maybe you try this:
List list = em
.createQuery("SELECT FUNCTION("'"+myLat+"'"+",'"+myLng+"')"
+ " FROM schemaName")
.getResultList();
source excample from web site
In this situation you get data from your own function. Is possible set to this function all query question which you need. Not only DISTANCE but all data which you would like to get.
Regarding the following example, is it possible to retrieve list of AnsweredQuestion instances as objects of Question?
#MappedSuperclass
public abstract class Question{
#Column(name="TITLE")
private String title;
...
}
#Entity
#Table(name="ANSWEREDQUESTION")
public class AnsweredQuestion extends Question
{
#Column(name="ANSWER")
private String answer;
...
}
It is very important for me to retrieve only a few columns since the descendant class has many.
I tried something as follows, but it still returns list of AnsweredQuestion:
queryStr = " select q from AnsweredQuestion q where ..."
TypedQuery<Question> query = entityManager.createQuery(queryStr, Question.class);
return query.setParameter( ... ).getResultList();
If you need to return a few fields, you can also select them and use the new operator:
TypedQuery<Sample> query = entityManager.createQuery("select new com.acme.sample.Sample(e.fieldA, e.fieldB) from AnsweredQuestion e", Sample.class);
return query.setParameter( ... ).getResultList();
JPA implementation will look for a Sample constructor (the path must be complete) and invoke it while transforming the result. It is pretty handy (at the cost of creating new classes to represent the result) to avoid returning everything the database has to return :)
I use the entity manager to save data for several types like int byte string double etc and this works fine
I added field to the entity class type bigDecimal and I can i see while debug the code that the object contain the
values type bigDecimal .
when i read the data from the table i get entries for all the types but not for the bigDecimal(got 0)
any idea what could be the reason for that.
I verify that class contain get and set for the bigDecimal.
BTW I use derby DB with eclipselink
something strange happen which is inconsistent behavior that I debug the process and
two times i able to see the bigdecimal data ...
This is the entity
#Entity
public class emp {
#Id
#GeneratedValue(strategy = GenerationType.TABLE)
private int id;
private String firstName;
private String lastName;
private BigDecimal bigDecimal;
This is the code to save the data,here object contain the all the values
entityManager.getTransaction().begin();
entityManager.persist(object);
entityManager.getTransaction().commit();
Here is the code that read the data
factory = Persistence.createEntityManagerFactory("abc");
EntityManager entityManager = factory.createEntityManager();
String className = classOjc.toString();
Query query = entityManager.createQuery("SELECT p FROM " + className + " p");
#SuppressWarnings("rawtypes")
List resultList = query.getResultList();
System.out.println(resultList.size());
for (Object result : resultList) {
System.out.println(result.toString());
}
I am having trouble using a native query in hibernate to alias a bean that contains enum properties. I am getting an InvocationTargetException when query.list() is called. My example is below:
#Entity(name = "table1")
public class Class1 {
#Column(name = "col1")
#NotNull
private Integer prop1;
#Column(name = "col2")
#NotNull
private String prop2;
#Column(name = "col3", length = 6)
#Enumerated(value = EnumType.STRING)
private MyEnumType prop3;
// ... Getters/Setters...
}
public List getClass1List(){
String sql = "select col1 as prop1, col2 as prop2, col3 as prop3 from table1";
Session session = getSession(Boolean.FALSE);
SQLQuery query = session.createSQLQuery(sql);
query.addScalar("col1", Hibernate.INTEGER);
query.addScalar("col2", Hibernate.STRING);
query.addScalar("col3", Hibernate.STRING);
query.setResultTransformer(Transformers.aliasToBean(Class1.class));
return query.list();
}
During the query.addScalar("col3", Hibernate.STRING) call, I don't know what type to use for col3 (the enum type). Hibernate.String is not working! I have also tried to leave the type off entirely ( query.addScalar("col3") ) but I get the same InvocationTargetException. Can anyone help me out with this? My model cannot be changed and I am stuck with a native sql query. Any ideas are appreciated.
// In public List getClass1List() method:
// 1. DEFINE:
Properties params = new Properties();
params.put("enumClass", "enumerators.MyEnumType");
params.put("type", "12");
// 2. REPLACE:
// query.addScalar("col3", Hibernate.STRING);
// X
query.addScalar("col3", Hibernate.custom(org.hibernate.type.EnumType.class, params));
Firstly, you shouldn't use
private EnumType prop3;
but
private ActualEnum prop3;
Where ActualEnum is your own enum type (for example, Fruits to distinguish apples and oranges).
Second, you hibernate mapping is irrelevant when you use native sql.
Now, there are couple of options I can propose. You can try to use addEntity() instead of bunch of scalars. It's possible that Hibernate will recognize enum property and map correctly.
Other option is to have non public setter that would take string from database, convert it to enum and set actual property.
Finally, you can customize transformer. But it's probably most complex option.