Jpa createSQLQuery returns List<Object> instead of List<Employee> - sql

Trying to make an sql query to get as a result a list of Class "EmployeeCardOrderLink". But this code always returns me an list of Object. Casts doesn't working. I got the right data in this list, but it's just object. In debug i can call methods(Idea suggest according interface of my class), but then i got "class Object doesn't have a such method". And i can't use TypedQuery cause i have old JPA version, it doesn't support this.
#Repository
public class EmployeeCardOrderLinkDAOImpl extends AbstractBasicDAO<EmployeeCardOrderLink> implements EmployeeCardOrderLinkDAO {
//....
#Override
public List<EmployeeCardOrderLink> getLinksByOrderNumber(Integer num) {
List<EmployeeCardOrderLink> result = (ArrayList<EmployeeCardOrderLink>) getSessionFactory().getCurrentSession().createSQLQuery("select * from employee_card_order_links " +
"where trip_order_id = " + num).list();
return result;
}}

You use Hibernate (not JPA), if you are using Session. Hibernate is JPA provider of course. You have to use EntityManager and other related things to use JPA.
You don't need SQL here. SQL always returns list of objects (if you don't use transformers to DTO objects).
Just use HQL (JPQL in JPA)
To get all EmployeeCardOrderLink
getSessionFactory().getCurrentSession()
.createQuery("select link from EmployeeCardOrderLink link").list();
Query "from EmployeeCardOrderLink" will work for Hibernate too (for JPA will not work).

Related

How to make JpaRepository without types, or to make jpa repo with only queries?

I have a couple repositories to work with entities (add,update, delete etc.). And I want to use JpaRepository to fetch statistic data only with #Queries methods, with no update, delete and other CRUD methods. Is there in spring JPA some solution for this case? If I use JpaRepository<PaymentList,Long> I bind to he PaymentList type and get CRUD methods, but to add or delete entities I have distinct repo, and if I use JpaRepository without types I get exception. One of the solutions is to owerride methods from JpaRepository and throw exception while using them, but it looks a bit ugly.
Here is the example of my repository:
#Repository
public interface StatisticRepo extends JpaRepository<PaymentList,Long> {
#Query("SELECT pd.date, SUM(pd.totalPayment) " +
"FROM PaymentDetails pd WHERE pd.date BETWEEN :date_from AND :date_until " +
"GROUP BY pd.date")
List getDailyExpensesStatistic(#Param("date_from") Date dateFrom,
#Param("date_until") Date dateUntil);
}`
The best solution that I found is to use org.springframework.data.repository.Repository. No matter with what type of entity or id. It don't have any methods to store or get data. Maybe someone has better solution...

Pageable usage with Query Annotation

Can I use Pageable attribute in Spring Data R2dbc repositories with #Query annotation? For example;
public interface PartyRepository extends ReactiveCrudRepository<Party,String> {
#Query("select * from party order by id")
Flux<Party> getParties(Pageable pageable);
}
It gives "org.springframework.data.repository.query.ParameterOutOfBoundsException : Invalid parameter index! You seem to have declared too little query method parameteres!"
Is there any way to use pagination in spring Data R2dbc repositories?
Thanks.
This is not supported by R2DBC and probably never will.
But you can adjust the query string with SpEL expressions manually to include paging. For MySQL, in your example, this could look like this:
#Query("SELECT * FROM party ORDER BY id LIMIT :#{[0].offset},:#{[0].pageSize}")
Flux<Party> getParties(Pageable pageable);
The [0] part indicates which argument in your argument list is the Pageable.

Spring data rest - expose default methods

I have a Person Repository as follows
#RepositoryRestResource
public interface PersonRepository extends Repository<Person, String> {
List<Person> findAll();
default List<Person> findNewPersons() {
return findByStartDateAfter(LocalDate.now().minusMonths(3));
}
List<Person> findByStartDateAfter(LocalDate date);
}
I am not able to expose the default method through rest.. is there a way to do it without creating an implementation of the repo ?
I faced a similar problem, and was able to solve it using a SpEL expression inside an HQL query in a #Query annotation.
While nowhere near as clean as using a default method, this was the tidiest way I could find without writing a custom controller or introducing a custom implementation with a new DSL library or something for just this one query.
#Query("select p from Person p where p.startDate > :#{#T(java.time.LocalDate).now().minusMonths(3)}")
List<Person> findNewPersons();
My actual query was different so I might have typoed the syntax here, but the idea is the same and it worked for my case (I was using a LocalDate parameter and finding timestamps on that day by using a findByTimestampBetween style query).

How to use group_concat in hibernate criteria?

I wrote a query in mysql using group_concat like
SELECT c1,group_concat(c2) FROM table1 where sno in(1,4,8,10) group by c1;
and gives my expected result.
Now the same query I want to write using hibernate criteria.
You have two options (depending on your hibernate version).
Override the dialect class
any hibernate version
You will need to subclass your dialect to add group_concat()
Introduce the dialect override class
Create the following class somewhere in your app (e.g. util package)
package com.myapp.util;
import org.hibernate.dialect.MySQL5Dialect;
import org.hibernate.dialect.function.StandardSQLFunction;
import org.hibernate.type.StandardBasicTypes;
public class MySQLCustomDialect extends MySQL5Dialect {
public MySQLCustomDialect() {
super();
registerFunction("group_concat",
new StandardSQLFunction("group_concat",
StandardBasicTypes.STRING));
}
}
Map the dialect override class to boot properties
Add the following property to your application.properities
spring.jpa.properties.hibernate.dialect = com.myapp.util.MySQLCustomDialect
Use JPA Metadata Builder Contributor
hibernate 5.2.18 or newer only
Introduce metadata builder class
Create the following class, remember to add package & resolve imports.
public class SqlFunctions implements MetadataBuilderContributor {
#Override
public void contribute(MetadataBuilder metadataBuilder) {
metadataBuilder.applySqlFunction( "group_concat",
new StandardSQLFunction( "group_concat",
StandardBasicTypes.STRING ) ); }
}
Map new class in application boot properties
Leave the dialect properties as is
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect
spring.jpa.properties.hibernate.metadata_builder_contributor = com.myapp.util.SqlFunctions
Simple answer is No
Why?
Hibernate support only common function/syntax used in multiple database. There ain't any group_concat function in Microsoft SQL Server and may be in other database as well.
Solution:
You have to execute it as Simple SQL Query.
Finally i go through like below code and got expected result
String query="select c1,group_concat(c2) from table1 where sno in (:pageIds) group by c1";
SQLQuery sqlQuery= session.createSQLQuery(query);
sqlQuery.setParameterList("pageIds", myList);
List list= sqlQuery.list();
c1 group_concat(c2)
aaa valu1,value2
bbb value3
ccc value4,value5,value6
Please refer following code snippets
Criteria cr = session.createCriteria(table1.class);
cr.add(Restrictions.in("sno",snoarray));
criteria.setProjection("c1");
criteria.setProjection(Projections.groupProperty("c1"));

Querying using OData and asp.net MVC webapi against a NHibernate database

I doubt this is just specific to NHibernate. But I have code as follows....
public class ClientController : ApiController
{
// GET /api/<controller>
public IQueryable<Api.Client> Get()
{
return Repositories.Clients.Query().Select(c => Mapper.Map<Client, Api.Client>(c));
}
I basically want to Query the database using the Odata criteria.... get the relevant 'Client' objects, and the convert them to the DTO 'Api.Client'.
But... the code as is, doesn't work. Because NHibernate doesn't know what to do the with the Mapper.... It really wants the query to come before the .Select. But I'm not sure I can get the Odata Query first?
It will work if I do
return Repositories.Clients.Query().Select(c => Mapper.Map<Client, Api.Client>(c)).ToList().AsQueryable();
But that's a bit sucky as you have to get ALL the clients from the database to do the OData query on.
Is there anyway to get the "Select" to happen after the OData query? Or another way to approach this?
I did not test it yet but the Open Source project NHibernate.OData could be useful for you.
The problem is that you are trying to execute C# code (Mapper.Map) inside the NH call (that is translated to SQL)
You'd have to map Api.Client manually, or create a Mapper implementation that returns an Expression<Func<Client, Api.Client>> and pass it directly as a parameter to Select().
Even with that, I'm not sure if NHibernate will translate it. But you can try.
AutoMapper supports this scenario with the Queryable Extensions
public IQueryable<Api.Client> Get() {
return Repositories.Clients.Query().Select(c => Mapper.Map<Client, Api.Client>(c));
}
becomes
public IQueryable<Api.Client> Get() {
return Repositories.Clients.Query().ProjectTo<Api.Client>(mapper.ConfigurationProvider);
}