I have a query that map to a Custom Object :
#Query("SELECT new com.mypackage.CmcXml(c.nom, c.prenom, c.genre "+
"FROM Cmc c")
List<CmcXml> getExportCmc();
So I get this kind of result :
{"NOM1", "PRENOM1", "GENRE1"},
{"NOM2", "PRENOM2", "GENRE2"},
{"NOM3", "PRENOM3", "GENRE3"}
I would like to have an counter that increment while retrieving the data :
#Query("SELECT new com.mypackage.CmcXml(myCounter, c.nom, c.prenom, c.genre "+
"FROM Cmc c")
List<CmcXml> getExportCmc();
The result I want :
{1, "NOM1", "PRENOM1", "GENRE1"},
{2, "NOM2", "PRENOM2", "GENRE2"},
{3, "NOM3", "PRENOM3", "GENRE3"}
Is it possible to do it in the #Query or do I have to go through all the list after the request ?
No , row number is not supported in jpa/hibernate. you have to use native query.
This is not possible in JPA as JPA operates to entities and entities are in turn mapped to tables in database. Row number corresponds to a result set and not actually exists in database table.
You can try something as below using native query depends on your database.
SELECT #rownumber\\:=#rownumber+1 as rownumber, column From Table
Or as JB Nizet suggested in comments, you can use your own logic to map those objects to objects with counter.
Related
I have a table called "Endoso", this table has the properties of "id", "numEndoso","endosos_por_dia". The "numEndoso" is the id of the envio(id of table EnvioRemesa), and the "endosos_por_dia" property is a calculated property as I put below.
select count(*)
from documento d
inner join remesa r
on r.id = d.remesa_id
inner join envio_remesa er
on r.id = er.remesa_id
where r.id=?
What I want and can't do, is that for example when I calculate endosos_por_dia if 8 documents turn out, create 8 different records in my database, increasing from 1 to 8.And how could I put my calculated property query on my entity Endoso and it will be reflected in the database? How can I do this in hibernate?
You can use a Formula:
#Formula("(select count(*) ... where r.id=numEndoso)")
public int getEndososPorDia() {
return endososPorDia;
}
Note that numEndoso in the SQL fragment refers to the ID of your entity, you might need to adapt it because I assumed that it was the name of the column.
This will make the endososPorDia field read-only as far as Hibernate is concerned, you will need to modify the underlying data (add new documents) and then refresh the entity to update the value
I have a query that has more columns then what my entity class has.
In order to not let hibernate complaints, I have to add an annotation to the field like
#Transient
private Integer count;
But by doing this makes hibernate not able to map count. Let's say my query is
session.createSQLQuery("SELECT p.*, count(p.id), sqrt(1+2) as distance FROM post p group by p.id")
I know the query doesn't make any logical sense. This is just for example. The columns return from query above will have everything in post and two extra columns, count and distance. I wanted to map the result to my entity with count and distance are annotated with #Transient, or if there's a better way to map the result. I'm more than happy to do so. The goal is not to do this in an entity but a class with mapped result. I've tried calling addEntity() but doesn't seem to help.
You can use Result Set Transformer to achieve this.
Step 1 ) Create a new DTO class with all the fields that you query going to return
Step 2 ) Add the below line
setResultTransformer( Transformers.aliasToBean(DTO.class))
Example :
List resultWithAliasedBean = session.createQuery(
"SELECT p.*, count(p.id), sqrt(1+2) as distance FROM post p group by p.id")
.setResultTransformer(Transformers.aliasToBean(DTO.class))
.list();
DTO dto = (DTO) resultWithAliasedBean.get(0);
Note : Make sure the field names in the DTO class match the column name which your query is returning.
I see that you are using Hibernate so Yathish answer works fine.
But if you want to do it with JPA spec then you can use Result Set Mapping
Query q = em.createNativeQuery(
"SELECT c.id, c.name, COUNT(o) as orderCount, AVG(o.price) AS avgOrder " +
"FROM Customer c " +
"JOIN Orders o ON o.cid = c.id " +
"GROUP BY c.id, c.name",
"CustomerDetailsResult");
#SqlResultSetMapping(name="CustomerDetailsResult",
classes={
#ConstructorResult(targetClass=com.acme.CustomerDetails.class,
columns={
#ColumnResult(name="id"),
#ColumnResult(name="name"),
#ColumnResult(name="orderCount"),
#ColumnResult(name="avgOrder", type=Double.class)})
})
There you have to specifiy the mappin of the columns from the SQL result set to the DTO.
And if you think this is to complicated there is a open source project called QLRM (Query Lanaguage Result Mapper) that mapps any SQL statement to a POJO.
http://simasch.github.io/qlrm/
And last but not least if you will do extensive SQL processing why not have a look at jOOQ: https://www.jooq.org/
My query like this,
String sql="select p.productName,p.extendedFlag from product p where productId=? and productVersion=?";
SqlQuery sqlQuery=session.createSQLQuery(sql).addEntity(Product.class);
sqlQuery.setParameter(0,"newprofin2");
sqlQuery.setParameter(1,"newprofin2");
List product =sqlQuery.list();//error at this line
Product p=(Product)product.get(0);
please Help me,
and i am using Hibernate 3.
If you want to return the result as an entity you need to use "select * ..." (so hibernate can map all the column annotations) otherwise you have to stick with selecting only scalar values that are not mapped to the entity and need to be processed on a column basis.
Examples:
http://www.tutorialspoint.com/hibernate/hibernate_native_sql.htm
I am using play framework for the first time and I need to link objects of the same type. In order to do so I have added a self referencing many to many relationship like this:
#ManyToMany(cascade=CascadeType.ALL)
#JoinTable(name="journal_predecessor", joinColumns={#JoinColumn(name="journal_id")}, inverseJoinColumns={#JoinColumn(name="predecessor_id")})
public List<Journal> journalPredecessor = new ArrayList<Journal>();
I obtain the table journal_predecessor which contains the two columns: journal_id and predecessor_id, both being FKs pointing to the primary key of the table journal.
My question is how can I query this table using raw queries if I am using H2 in-memory database. thanks!
Actually it was very easy. I just needed to create an instance of SqlQuery to create a raw query:
SqlQuery rawQuery = Ebean.createSqlQuery("SELECT journal_id from journal_predecessor where journal_id=" + successorId + " AND predecessor_id=" + predecessorId);
And because i just needed to check weather a row exists or not, I find the size of the set of the results returned by the query:
Set<SqlRow> sqlRow = rawQuery.findSet();
int rowExists = sqlRow.size();
Sample database table:
ID = 1, msgFrom = 'Hello', foobar = 'meh'
ID = 2, msgFrom = 'Goodbye', foobar = 'comments'
ID = 3, msgFrom = 'Hello', foobar = 'response'
Sample desired output (generated by hibernate query):
ID = 1, msgFrom = 'Hello', foobar = 'meh'
ID = 2, msgFrom = 'Goodbye', foobar = 'comments'
In the above example, the third record would be excluded from the results since the msgFrom column is the same. Let's say the Java/Hibernate class is called Message. I would like the results to be returned as a list of Message objects (or Objects that can be cast to Message, anyway). I want to use the Criteria API if possible. I saw this example on SO and it seems similar but I cannot implement it correctly as of yet.
select e from Message e
where e.msgFrom IN (select distinct m.msgFrom
from Message m
WHERE m.msgTo = ?
AND m.msgCheck = 0");
The reason I am doing this is to have the filtering of distinct records done on the database, so I am not interested in answers where I have to filter anything on the application server.
edit: Article showing basically what I want to do. http://oscarvalles.wordpress.com/2008/01/28/sql-distinct-on-one-column-only/
Please try this and let me know
DetachedCriteria msgFromCriteria = DetachedCriteria.forClass(Message.class);
ProjectionList properties = Projections.projectionList();
properties.add(Projections.groupProperty("messageFrom"));
properties.add(Projections.min("id"),"id");
msgFromCriteria.setProjection(properties);
Criteria criteria = s.createCriteria(Message.class);
criteria.add(Subqueries.propertiesIn(new String[]{"messageFrom","id"},
msgFromCriteria));
List<Message> list = criteria.list();
for(Message message:list){
System.out.println(message.getId()
+"-------"
+message.getMessageFrom()
+"-----"
+message.getFoobar());
}
The difficulty with this query is not so much with Hibernate, per se, but with the relational model in general. In the example, you say you expect rows 1 and 2, but why wouldn't you just as easily expect rows 2 and 3? It would be an arbitrary decision whether to return row 1 or row 3 since they both have the same value in the msgFrom field. Databases won't make arbitrary decisions like this. That's why distinct must be applied to the entire list of select columns, not a subset. There are database-specific ways of grabbing the first matching rows. For example, have a look at
SELECT DISTINCT on one column
Sometimes there will be a date column that you can use to decide which of the matching rows to return, but again the queries get somewhat complex:
How can I SELECT rows with MAX(Column value), DISTINCT by another column in SQL?
Fetch the row which has the Max value for a column
If you don't care about any of the other columns, you can just use a simple distinct, combined with Hibernate's constructor syntax (not tested):
select new Message(msgFrom) from (select distinct msgFrom from Message)
but you have to accept throwing away all the other columns.
In the end, I often end up just doing this in code as a post query filter. Another option is to create a another table, say CurrentMessage, that includes msgFrom as part of the key. There will be more work in keeping this table up to date (you need to update a row everytime you add a row to the Message table) but querying will be much easier.
DetachedCriteria msgFromCriteria = DetachedCriteria.forClass(Message.class);
msgFromCriteria.setProjection(Projections.distinct(Projections.property("msgFrom")));
....
Criteria criteria = getSession().createCriteria(Message.class);
criteria.add(Subqueries.propertyIn("msgFrom", msgFromCriteria));
criteria.list();