I have spring dao bean called HostelDaoImpl. It uses hibernate criteria api to retrieve results.
public class HostelDaoImpl extends AbstractGenericDao<Hostel, Integer> implements HostelDao {
public HostelDaoImpl() {
super(Hostel.class);
}
public List<Hostel> findHostelBy(HostelSearch hs) {
Criteria criteria = currenSession().createCriteria(Hostel.class);
criteria.setReadOnly(true);
Calendar beginDate = hs.getBeginDate();
String country = hs.getCountry();
if (beginDate != null)
criteria.add(Restrictions.le("beginDate", beginDate));
if (country != null) {
criteria.add(Restrictions.eq("country", country));
}
criteria.setProjection(Projections.rowCount());
Integer foundHostelsCount = (Integer) criteria.uniqueResult();
if (foundHostelsCount > 100) {
// do pagination
}
}
}
Now in place of those comments I need pagination.
I want to create Criteria only once and then store Criteria somewhere and call Criteria's setFirstResult and setMaxResults each time when user requests new portion of data.
Where to store Criteria if spring bean HostelDaoImpl is singleton and if I create instance variable Criteria criteria it is concurrently unsafe.
Where to store Criteria so that it is thread safe?
But if you know better way to achieve hibernate pagination in spring bean please provide it.
Thanks!
You can use CRUD repositories. It supports pagination
http://docs.spring.io/spring-data/data-commons/docs/1.6.1.RELEASE/reference/html/repositories.html
I'm using the Jquery plugin JQGrid to show in a table the results, and it's very easyly to hibernate pagination.
http://jqgrid.com/
You can use pageRequest for pagination.
follow the steps on this link.
This link is very helpful. The link explains everything till JSP page.
Related
My project involves using GraphQL within a Spring Boot app. For demonstration purposes, here is my GraphQL schema:
type Company{
name: String,
parentOrganization: String,
flag:Int
}
I'm still learning Spring Boot and JPA, so I use spring-boot-starter-data-jpa for all the JPA, Hibernate, etc.
My problem is, when someone queries only for name and organization, Hibernate queries for all the columns and GraphQL picks the columns requested.
#Repository
#Transactional
public interface CompanyRepository extends JpaRepository<Company,Long> {
}
The above code doesn't really give me any flexibility in limiting the columns that are queried. I've tried using Hibernate's Criteria API as well, but whichever way I go, I get this error:
Unable to locate appropriate constructor on class [packagee.entity.company]. Expected arguments are: java.lang.String, java.lang.String [select new package.entity.Company(generatedAlias0.company, generatedAlias0.organization) from package.entity.Company as generatedAlias0]
Below is the code for my Criteria implementation:
public static List<Company> get(EntityManager em, List<String> fieldsAsked){
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Company> cq = cb.createQuery(Company.class);
Root<Company> root = cq.from(Company.class);
List<Selection<?>> selectionList = new LinkedList<Selection<?>>();
for(String name: fieldsAsked){
selectionList.add(root.get(name));
}
cq.multiselect(selectionList);
return em.createQuery(cq).getResultList();
}
How do I get limited columns from Hibernate? I've seen many answers online that ask to make appropriate constructor in the entity class, but that's not really possible for me because my entity parameters are mostly Strings and I cant make constructors for all the permutations possible (because I'm using GraphQL, the control of what to query really goes to the end user of my project).
What should I do? Thanks in advance!
What you want to do is not really possible with Hibernate directly, but you can checkout Blaze-Persistence Entity-Views which also has a GraphQL integration that supports exactly what you are looking for. See https://persistence.blazebit.com/documentation/1.6/entity-view/manual/en_US/#graphql-integration
Here is a sample project that shows how you can use this: https://github.com/Blazebit/blaze-persistence/tree/master/examples/spring-data-graphql
Solution 1:
You can create a new DTO class which will be returned by your query.
The DTO class:
public class CompanyDTO(){
//fields,constructor
}
And in the repository:
#Query(value = "SELECT new com.example.dto.companyDTO" +
"(c.name,c.parentOrganization)" +
" FROM Company c")
List<CompanyDTO>findCompanySelectedColumns(PageRequest pageable);
Solution 2(clean solution):
You can use interface. Do not implement the interface.
interface customCustomer{
String getName();
String getParentOrganization();
}
In repository:
List<CustomCustomer>findAllByNameAndParentOrganization();
#Repository
public interface UserDao extends User {
public List<User> findByFirstname(String firstname);
}
How could I use above code to retrieve all records?
I tried findByFistname(null);, it doesn't work...
I don't want to use findByFirstname(); because it's possible to have parameter.
Hope you all understand.
Have you considered using a spring data specification? In spring data a specification is a way to wrap the JPA criteria api.
The idea behind the JPA Criteria api is to generate queries programatically, by defining query objects.
Once you have encapsulated the criteria in a specification objects, a single findAll method can be used in a number of scenarios. For example programatically add criteria based input form the user, such as additional search filters etc.
To use this feature a repo will need to extend "JpaSpecificationExecutor"
public interface UserRepository extends JpaRepository<User>, JpaSpecificationExecutor {
List<T> findAll(Specification<T> spec);
}
The find method can then be called with multiple criteria, or the criteria can be built dynamically based on the situation:
List<User> users = userRepository.findAll(where(userLastNameIs("John")).and(userIsArchived()));
Alternatively you can also try query by exampe. The idea here is to provide the actual domain object with the populated search fields to an example matcher. Configure the example matcher to control the search and pass it to the findAll method.
Again the repo will need to implement an interface. Check the documentation for the detailed pros/cons of each approach.
Person person = new Person();
person.setFirstname("Dave");
ExampleMatcher matcher = ExampleMatcher.matching()
.withIgnorePaths("lastname")
.withIncludeNullValues()
.withStringMatcherEnding();
Example<Person> example = Example.of(person, matcher);
List<Person> people = personRepository.findAll(example);
You should extend your repository from JpaRepository. Be careful with name of repository (It should follow convention). After you inject your UserRepository bean you will have already implemeted by spring data crud methods like findOne(), findAll(), delete() etc.
#Repository
public interface UserRepository extends JpaRepository<User, Long> {
//assume your primary key is Long type
}
Also will be useful documentation
As I got from comments you're trying to achieve ignorance of null values of passed parameters (instead of retrieving all records by findAll()).
Unfortunately, currently, it's not supported by Spring .
You could leverage the #Query annotation and write the query manually in such manner:
#Query("select u from User u where "
+ "(:firstname is null or u.firstname = :firstname)"
+ "(:lastname is null or u.lastname = :lastname)"
)
public List<User> findUserByFirstNameAndLastName(
#Param("firstname") String firstname,
#Param("lastname") String lastname
);
https://spring.io/blog/2011/02/10/getting-started-with-spring-data-jpa/
This is very good tutorial of Spring Data. I suggest you to start with it. tutorial of Spring Data. If you want to go deeper you can read the documentation.
http://docs.spring.io/spring-data/data-commons/docs/1.6.1.RELEASE/reference/html/repositories.html
I'm refactoring a code base to get rid of SQL statements and primitive access and modernize with Spring Data JPA (backed by hibernate). I do use QueryDSL in the project for other uses.
I have a scenario where the user can "mass update" a ton of records, and select some values that they want to update. In the old way, the code manually built the update statement with an IN statement for the where for the PK (which items to update), and also manually built the SET clauses (where the options in SET clauses can vary depending on what the user wants to update).
In looking at QueryDSL documentation, it shows that it supports what I want to do. http://www.querydsl.com/static/querydsl/4.1.2/reference/html_single/#d0e399
I tried looking for a way to do this with Spring Data JPA, and haven't had any luck. Is there a repostitory interface I'm missing, or another library that is required....or would I need to autowire a queryFactory into a custom repository implementation and very literally implement the code in the QueryDSL example?
You can either write a custom method or use #Query annotation.
For custom method;
public interface RecordRepository extends RecordRepositoryCustom,
CrudRepository<Record, Long>
{
}
public interface RecordRepositoryCustom {
// Custom method
void massUpdateRecords(long... ids);
}
public class RecordRepositoryImpl implements RecordRepositoryCustom {
#Override
public void massUpdateRecords(long... ids) {
//implement using em or querydsl
}
}
For #Query annotation;
public interface RecordRepository extends CrudRepository<Record, Long>
{
#Query("update records set someColumn=someValue where id in :ids")
void massUpdateRecords(#Param("ids") long... ids);
}
There is also #NamedQuery option if you want your model class to be reusable with custom methods;
#Entity
#NamedQuery(name = "Record.massUpdateRecords", query = "update records set someColumn=someValue where id in :ids")
#Table(name = "records")
public class Record {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
//rest of the entity...
}
public interface RecordRepository extends CrudRepository<Record, Long>
{
//this will use the namedquery
void massUpdateRecords(#Param("ids") long... ids);
}
Check repositories.custom-implementations, jpa.query-methods.at-query and jpa.query-methods.named-queries at spring data reference document for more info.
This question is quite interesting for me because I was solving this very problem in my current project with the same technology stack mentioned in your question. Particularly we were interested in the second part of your question:
where the options in SET clauses can vary depending on what the user
wants to update
I do understand this is the answer you probably do not want to get but we did not find anything out there :( Spring data is quite cumbersome for update operations especially when it comes to their flexibility.
After I saw your question I tried to look up something new for spring and QueryDSL integration (you know, maybe something was released during past months) but nothing was released.
The only thing that brought me quite close is .flush in entity manager meaning you could follow the following scenario:
Get ids of entities you want to update
Retrieve all entities by these ids (first actual query to db)
Modify them in any way you want
Call entityManager.flush resulting N separate updates to database.
This approach results N+1 actual queries to database where N = number of ids needed to be updated. Moreover you are moving the data back and forth which is actually not good too.
I would advise to
autowire a queryFactory into a custom repository
implementation
Also, have a look into spring data and querydsl example. However you will find only lookup examples.
Hope my pessimistic answer helps :)
I am relatively new to hibernate. I am developing a java application which uses hibernate to do the basic CRUD operations. I wanted to add some logic specifically when I am doing a read from database. For all the operations, I do a session.createQuery to generate the query and do the operation. Is there some flag available in session object or any other related objects which differentiates a read/find operation from the rest of the CRUD operations. I wanted to add the logic where I create the HQL query from the session object.
Thanks in advance for any help in this regard.
you can use criteria, for example to find all objects related to the class USER:
public List<USER> findAllOBJECTS() {
Criteria criteria = createEntityCriteria().addOrder(Order.asc("nom"));;
return (List<USER>) criteria.list();
}
or if you want to search for a user by his login for example:
public USER findByLOGIN(String login) {
Criteria crit = createEntityCriteria();
crit.add(Restrictions.eq("login", login));
USER user = (USER)crit.uniqueResult();
return user;
}
I am examining example Blog example of CouchDB. I use Ektorp at Spring for CouchDB. I wanted to implement it into my application. I have users at my couch db when I use that:
#GenerateView
#Override
public List<User> getAll() {
ViewQuery q = createQuery("all")
.descending(true)
.includeDocs(true);
return db.queryView(q, User.class);
}
However it returns just last record. Any ideas to get all users?
It works well problem was about db names that's written at Spring configuration file.