Does Spring Data JPA have any way to count entites using method name resolving?
JavaSpringSpring Data-JpaJava Problem Overview
Spring Data JPA supports counting entities using specifications. But does it have any way to count entities using method name resolving? Let's say I want a method countByName
to count entities with specific name, just like a method findByName
to fetch all entities with specific name.
Java Solutions
Solution 1 - Java
As of Spring Data 1.7.1.RELEASE you can do it with two different ways,
- The new way, using query derivation for both count and delete queries. Read this, (Example 5). Example,
public interface UserRepository extends CrudRepository<User, Integer> {
long countByName(String name);
}
- The old way, Using
@Query
annotation.
Example,
public interface UserRepository extends CrudRepository<User, Integer> {
@Query("SELECT COUNT(u) FROM User u WHERE u.name=?1")
long aMethodNameOrSomething(String name);
}
or using @Param
annotation also,
public interface UserRepository extends CrudRepository<User, Integer> {
@Query("SELECT COUNT(u) FROM User u WHERE u.name=:name")
long aMethodNameOrSomething(@Param("name") String name);
}
Check also this so answer.
Solution 2 - Java
As long as you do not use 1.4 version, you can use explicit annotation:
example:
@Query("select count(e) from Product e where e.area.code = ?1")
long countByAreaCode(String code);
Solution 3 - Java
JpaRepository also extends QueryByExampleExecutor. So you don't even need to define custom methods on your interface:
public interface UserRepository extends JpaRepository<User, Long> {
// no need of custom method
}
And then query like:
User probe = new User();
u.setName = "John";
long count = repo.count(Example.of(probe));
Solution 4 - Java
Working example
@Repository
public interface TenantRepository extends JpaRepository< Tenant, Long > {
List<Tenant>findByTenantName(String tenantName,Pageable pageRequest);
long countByTenantName(String tenantName);
}
Calling from DAO layer
@Override
public long countByTenantName(String tenantName) {
return repository.countByTenantName(tenantName);
}
Solution 5 - Java
This feature has been added in version 1.4 M1
Solution 6 - Java
Apparently it is implemented now DATAJPA-231
Solution 7 - Java
According to Abel, after the version 1.4 (tested in version 1.4.3.RELEASE) is possible doing this way:
public long countByName(String name);
Solution 8 - Java
Thanks you all! Now it's work. DATAJPA-231
It will be nice if was possible to create count…By… methods just like find…By ones. Example:
public interface UserRepository extends JpaRepository<User, Long> {
public Long /*or BigInteger */ countByActiveTrue();
}
Solution 9 - Java
@Autowired
private UserRepository userRepository;
@RequestMapping("/user/count")
private Long getNumberOfUsers(){
return userRepository.count();
}
Solution 10 - Java
I have only been working with it for a few weeks but I don't believe that this is strictly possible however you should be able to get the same effect with a little more effort; just write the query yourself and annotate the method name. It's probably not much simpler than writing the method yourself but it is cleaner in my opinion.
Edit: it is now possible according to DATAJPA-231
Solution 11 - Java
According to the issue DATAJPA-231 the feature is not implemented yet.
Solution 12 - Java
If anyone wants to get the count based on multiple conditions than here is a sample custom query
@Query("select count(sl) from SlUrl sl where sl.user =?1 And sl.creationDate between ?2 And ?3")
long countUrlsBetweenDates(User user, Date date1, Date date2);
Solution 13 - Java
In my opinion the other solutions do not answer the question. According to the sentence
> Spring Data JPA supports counting entities using specifications.
he wants to use JPA Specifications with name resolving. All the answers are pointing to the api without specifications.
As long as I know there is no repository implementation with specification and name resolving. The JpaSpecificationExecutor does not support it.
I had the same problem and created a custom repository where I used code like:
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<Long> query = builder.createQuery(Long.class);
Root<S> root = query.from(domainClass);
Path<Object> attribute = root.get(attributeName);
query.select(builder.countDistinct(attribute));
if(spec == null){
return em.createQuery(query);
}
Predicate predicate = spec.toPredicate(root, query, builder);
if(predicate != null){
query.where(predicate);
}
return em.createQuery(query);
The variable "attributeName" is a String with the name of the attribute.