How to query for boolean property with Spring CrudRepository? - java

I'm using Spring CrudRepository for database queries. How can I create a method signature (not writing SQL select statement myself) for a boolean property?
The following does not work:
class MyEntity {
private boolean active;
}
interface MyEntityRepository implements CrudRepository<MyEntity, Long> {
List<MyEntity> findActive(); //or also: findNotActive();
}

I would do:
interface MyEntityRepository implements CrudRepository<MyEntity, Long> {
List<MyEntity> findByActive(Boolean active);
}
Then the service layer would be
public class MyEntityServiceImpl implements MyEntityService{
public List<MyEntity> findActive() {
return myEntityRepository.findByActive(true);
}
}
UPDATE
As pointed out by #OliverGierke you could simplify your repository even more by doing:
interface MyEntityRepository implements CrudRepository<MyEntity, Long> {
List<MyEntity> findByActiveTrue(); //you could also use findByActiveFalse
}
For all the supported keywords you should see the section
Query creation
of the reference documentation

Related

Why Spring data JpaRepository method name complement does not work with Class type parameter?

I have a class like this:
#MappedSuperclass
public abstract class Foo implements Serializable, Cloneable {
private String id;
private Boolean deleted = Boolean.FALSE;
private Boolean active = Boolean.TRUE;
...
}
and a repository like this:
#NoRepositoryBean
public interface FooRepository<F extends Foo> extends JpaRepository<F, String> {
}
now the problem:
when I use class level type parameters(generics) like above, intellij does not make or complete spring-data`s named query but if I remove the generics like below then I can write named queries in the repository interface
#NoRepositoryBean
public interface FooRepository extends JpaRepository<Foo, String> {
Integer countAllByActive(boolean flag);
}
anybody knows why and is there any solution?

JpaRepository implementation- Lists vs. Sets

I'm building my first Spring Boot app using JPA and have setup my data repositories and services like this:
#Repository
public interface FooRepository extends JpaRepository<Foo, Long> {
Set<Foo> findAllByActiveInstallationIsNull();
}
Then a CrudService
public interface CrudService<T extends BaseEntity> {
Set<T> findAll();
T findById(Long id);
T save(T object);
void delete(T object);
void deleteById(Long id);
}
along with an example class service interface that extends it
public interface FooService extends CrudService<Foo> {
Set<Foo> findAllAvailable();
Foo getIfAvailable(Long id);
}
an abstract class for service implementations
public abstract class AbstractJpaService<T extends BaseEntity, R extends JpaRepository<T, Long>> implements CrudService<T> {
protected R repository;
public AbstractJpaService(R repository) {
this.repository = repository; }
#Override
public Set<T> findAll() {
return new HashSet<>(repository.findAll()); }
#Override
public T findById(Long id) {
return repository.findById(id).orElse(null); }
#Override
public T save(T object) {
return repository.save(object); }
#Override
public void delete(T object) {
repository.delete(object); }
#Override
public void deleteById(Long id) {
repository.deleteById(id); }
}
and finally an example of an actual service class that extends the above-mentioned one:
#Service
#Transactional
public class FooJpaService extends AbstractJpaService<Foo, FooRepository> implements FooService {
public FooJpaService(FooRepository repository) {
super(repository);
}
///
}
I wrote some service layer logic, controllers and once I was happy with the first iteration I've done some postman testing that worked without a hitch.
Then I took a step back and started writing some unit tests for my service classes only to realize that while findAll() in my services returns Set as I intended, the JpaRepository methods and by extension my own repos give List.
#Test
void findAll() {
Set<Foo> returnFooSet = new HashSet<>();
returnFooSet.add(new Foo(boo, 1d, 2d));
returnFooSet.add(new Foo(baz, 3d, 4d));
when(fooRepository.findAll()).thenReturn(returnFooSet);
Set<Foo> foos = service.findAll();
assertNotNull(foos);
assertEquals(2, foos.size());
}
resulting in thenReturn() method expecting a List.
Sorry for the wall of code, but I'm pretty new at this and very much confused so figured I'll provide excessive context even if most could have been assumed, since my newbie implementations may be weird and faulty.
So what gives?
I've read about the benefits of using Sets in JPA and most of the code examples I've seen use them.
My own findAllByArgument methods with Set returns like the ones you see in the repository have been working just fine, so I assume nothing stops me from overriding basic FindAll() methods in all of my repos (since CrudRepository seems to have just Iterable there), but that seems... off?
Should I be using Sets with JPA? What are good practices in this case?
I believe the only rule of thumb regarding List or Set in JPA world (with Hibernate under the hood) is to always use Set on a #ManyToMany relationship and never List.
Other than that I am not aware of anything else. Still, I can guess that maybe Set is better in terms of performance since it is unordered while List is ordered. Given that JpaRepository has a method that returns List this eventually better performance might not be relevant enough.

Spring Boot not fetching correct data from Oracle database

My code is as follows:
Repository:
#Repository
#Component
public interface SearchInventoryRepository extends JpaRepository<Inventory, String>{
#Query(nativeQuery = true, value = "select * from ORACLE_DATA1")
List<Inventory> findAllDatabases();
#Query(nativeQuery = true, value = "select count(*) from ORACLE_DATA1")
int getCount();
}
Service:
#Transactional
#Service
public class GetInventoryService {
#Autowired
private SearchInventoryRepository searchInventoryRepository;
public List<Inventory> findAllDatabases()
{
return searchInventoryRepository.findAllDatabases();
}
#Autowired
public int getCount()
{
return searchInventoryRepository.getCount();
}
}
Controller:
#RestController
#Component
public class GetInventoryController {
#Autowired
private GetInventoryService getInventoryService;
#CrossOrigin
#GetMapping("/getAll")
public List<Inventory> getAll()
{
return getInventoryService.findAllDatabases();
}
#CrossOrigin
#GetMapping("/getCount")
public int getCount()
{
return getInventoryService.getCount();
}
}
The following queries yield the correct result when I run them in SQL developer:
select * from ORACLE_DATA1;
select count(*) from ORACLE_DATA1;
However, in the spring api, many of the results are duplicates, and many results are not fetched. The count of results, remains the same in SQL Developer as well as when fetched through the API.
I have never come across such an issue before. Can anyone help?
1) There is no need to annotate with #Repository an interface that extends JpaRepository
2) It's not correct to annotate with #Component a class that already has a #Repository, #Service or #Controller annotation.
#Component simply marks the class as a bean, the others integrate this feature.
3) #Autowired is used to inject instances of the annotated type. This is not correct:
#Autowired
public int getCount()
{
return searchInventoryRepository.getCount();
}
4) You can use the default methods provided by JpaRepository instead of using #Query. E.g.:
searchInventoryRepository.findAll(); // already defined
and
searchInventoryRepository.count(); // already defined
I dont know why you are using native queries, but JpaRepository extends PagingAndSortingRepository, and PagingAndSortingRepository extends CrudRepository, and this provides, and I quote:
sophisticated CRUD functionality for the entity class that is being managed
Example:
public interface CrudRepository<T, ID extends Serializable>
extends Repository<T, ID> {
(1)
<S extends T> S save(S entity);
(2)
T findOne(ID primaryKey);
(3)
Iterable<T> findAll();
Long count();
(4)
void delete(T entity);
(5)
boolean exists(ID primaryKey);
(6)
// … more functionality omitted.
}
Among the existing methods, there are two that do what you need. It is not good to reinvent the wheel.
You can get more information from this link
https://docs.spring.io/spring-data/data-commons/docs/1.6.1.RELEASE/reference/html/repositories.html

Spring data couchbase documents java classes inheritance

My problem is, that spring data couchbase doesn't search for subclasses of searched class. For example:
Model:
#Document
class A {
#Id
String id
}
#Document
class B extends A {}
And repository:
public interface ARepository extends PagingAndSortingRepository<A, String>{
Page<A> findAll(Pageable pageable);
}
Spring data couchbase generate query, that has in where condition
_class="com.example.model.A"
But I want in this query search B documents too. Is some way, how can I do this? When I write own query, I must defining order, limit and offset in query and Pageable is not used. But I want use Pageable.
Consider generic interface based on inheritance.
Firstly create super class:
#Inheritance
public abstract class SuperClass{
#Id
private int id;
}
Then create your subclasses:
public class A extends SuperClass { /* ... */ }
public class B extends SuperClass { /* ... */ }
Create base repository:
#NoRepositoryBean
public interface SuperClassBaseRepository<T extends SuperClass>
extends PagingAndSortingRepository<T, Integer> {
public T findAll();
}
And then create SuperClass repository basing on base repo:
#Transactional
public interface SuperClassRepository extends SuperClassBaseRepository<SuperClass> { /* ... */ }
#Transactional
public interface ARepository extends SuperClassBaseRepository<A> { /* ... */ }
#Transactional
public interface BRepository extends SuperClassBaseRepository<B> { /* ... */ }
SuperClassRepository findAll() will search all A and B classes
We managed to make this work on Spring Data Couchbase 3.2.12. Here's what we did:
We figured out that mappers for each type were only being created if a repository existed for that type, so, besides our superclass repository...
public interface ARepository extends PagingAndSortingRepository<A, String> {
Page<A> findAll(Pageable pageable);
}
We created an empty repository for each of the subtypes such as:
public interface BRepository extends PagingAndSortingRepository<B, String>{
// No methods
}
The presence of this second repo warranted the existence of an appropriate mapper for B, so when findAll (or other methods) are invoked in ARepository, the mapper for each subclass is present. Having done this, we were able to get a list of A that were actually B instances.
Hope this helps and nobody has to lose any more time on this. :)

Repository design pattern - should there be one repo for every Dao?

i have a few DAOs in my app which access a database for CRUD operations. Lets say there News, weather and , sports DAO. So im confused on how many Repositories i would need. should i just use one repository say DataRepository and let me hold my database and all dao's. and encapsulate methods for the CRUD operations in it ? or should each DAO have its own repository ?
I mean a repository should return only data objects that the calling layer understands. so its like a encapsulation over the DAOs but im not sure if i should create one per DAO or just have one repo per app, etc.
If you read this article we begin to understand that the pattern is over engineered or over abstracted. Its turned into hiding detail vs minimizing query statements.
But it seems There should be a Repo per DAO as the interface itself looks like this:
interface Repository<T> {
void add(T item);
void remove(Specification specification);
List<T> query(Specification specification);
}
where T can be the type/table of data DAO accesses. Just need clarification now. Can you imagine i have 30 different types, so then i need 30 different Repo implementations. this is ridiculous. It seems the repository pattern itself is like a DAO, no different. im so confused.
I am not sure this is what all you looking for but In my application I am using described DAO pattern with Spring
So im confused on how many Repositories i would need.
IMHO you will need at least single Repository for each entity as they lead to simple design but since you are making them generic and they are up in hierarchy, can be used simply with child classes/interfaces
Below is the example
Interface to define all basic methods that to use commonly
public interface GenericDAO<T, ID extends Serializable> {
T findById(ID id, LockModeType lock);
void save(T entity);
T update(T entity);
List<T> findAll();
}
Generic Implementation
public abstract class GenericDAOImpl<T, ID extends Serializable> implements GenericDAO<T, ID> {
#PersistenceContext
protected EntityManager em;
private final Class<T> entityClass;
public GenericDAOImpl(Class<T> entityClass) {
this.entityClass = entityClass;
}
#Override
public T findById(ID id, LockModeType lock) {
return em.find(entityClass, id, lock);
}
#Override
public void save(T entity) {
em.persist(entity);
}
#Override
public T update(T entity) {
return em.merge(entity);
}
#Override
public List<T> findAll() {
CriteriaQuery<T> c = em.getCriteriaBuilder().createQuery(entityClass);
c.select(c.from(entityClass));
return em.createQuery(c).getResultList();
}
.
.
.
}
Foo class
#Entity
public class Foo implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
private String text;
}
Foo Repositiry
public interface FooRepositiry extends GenericDAO<Foo, Long> {
Foo findTextById(Long id);
}
Implemented Foo Repositiry
#Transactional
#Repository
public class FooRepoImpl extends GenericDAOImpl<Foo, Long> implements FooRepositiry {
public FooRepoImpl() {
super(Foo.class);
}
#Override
public Foo findTextById(Long id) {
CriteriaQuery<Foo> c = em.getCriteriaBuilder().createQuery(Foo.class);
// .
// .
// .
return em.createQuery(c).getSingleResult();
}
}
Same for Bar class
#Transactional
#Repository
public class BarRepoImpl extends GenericDAOImpl<Bar, Long> implements BarRepo {
public BarRepoImpl() {
super(Bar.class);
}
#Override
public List<Bar> findAllBarWithText(String text) {
CriteriaQuery<Bar> c = em.getCriteriaBuilder().createQuery(Bar.class);
return em.createQuery(c).getResultList();
}
}
Here this generic implementation needs two things to work: an EntityManager and an
entity class. A subclass must provide the entity class as a constructor argument. EntityManager is provided by using PersistenceContext or you can use getter-setter methods for the same. Since GenericDAOImpl is abstract threfore you cannot use it directly but Indirectly and most of the commnoly used methods are generic and up in hierarchy which makes them Ideal candidate to be reused.
You can read more about this from book Java Persistence with Hibernate 2nd Edition

Categories

Resources