Spring Boot 2.0.0.M2/Spring Data and findById method - spring

I'm trying to move my project to Spring Boot 2.0.0.M2
Now Spring Data uses Optional for findBy* methods, like:
Optional<T> findById(ID id);
I have a Neo4j entities that contain the id property, for example:
#NodeEntity
public class Tag {
private Long id;
}
#Repository
public interface TagRepository extends Neo4jRepository<Tag, Long>
Tag findById(Long tagId);
}
id is a plain property and not and entity identifier(PK).
Prior Spring Boot 2.0 I used repository.findOne() embedded method in order to look up entity by it's identifier(PK) and my custom repository.findById() in order to look up entity by its id property.
Right now with Spring Boot 2.0 we don't have findOne and instead of this we have findById method finds the entity by PK. Right now I don't know how to provide my custom repository.findById method i order to be able to look up entity by ID property(not PK). Please advise.

If the field tagId exists in the entity you can use
Tag findByTagId(long tagId);
if not use
#Query("select t from Tag t where t.tagId = :tagId")
Tag getByTagId(#Param("tagId") long tagId);

Related

Mapping a DTO to Entity with #Verion column-Spring Boot Hibernate

I have a DTO which need to be mapped to Entity with a #Version column in DB, and then to do update.
Before mapping I get the Entity from database (I need it because of some validations and comparations) and then use the mapper.
So, the code is like this:
Entity fromDB = getEntity(eDto.getId());
Entity forUpdate = mapper.toEntity(fromDB, eDto);
Mapper:
Entity toEntity(#MappingTarget Entity e, EntityDto eDto);
In EntityDto I have few columns and Version also. But after getting the Entity from DB it is in PersistenceContext and the version can not be changed, so even if I use the wrong Version number, I never get the Optimistic Lock Failure exception.
Any suggestion how can I resolve this issue?
UPDATE:
(here is an example)
user1 get the entity with id 1 and version 1 on UI
user1 make some changes on entity
in the meantime some other user have changed and saved the object to DB (now version is 2)
user1 call updateEntity with version 1 and it comes to my method for update
I take the entity from DB (and now the version is 2)
I map it to forUpdate (BUT HERE VERSION IS NOT MAPED because fromDB is in PersistenceContext and it is not allowed to change version)
the changes are made, and they should NOT be made because versions are not the same!
Not sure how helpful this is for you, but I think Blaze-Persistence Entity Views would be the perfect fit for your situation.
I created the library to allow easy mapping between JPA models and custom interface or abstract class defined models, something like Spring Data Projections on steroids. The idea is that you define your target structure(domain model) the way you like and map attributes(getters) via JPQL expressions to the entity model.
A DTO model for your use case could look like the following with Blaze-Persistence Entity-Views:
#UpdatableEntityView
#EntityView(Entity.class)
public interface EntityDto {
#IdMapping
Long getId();
String getName();
Set<SubDto> getRoles();
#EntityView(SubEntity.class)
interface SubDto {
#IdMapping
Long getId();
String getName();
}
}
Querying is a matter of applying the entity view to a query, the simplest being just a query by id.
EntityDto a = entityViewManager.find(entityManager, EntityDto.class, id);
The Spring Data integration allows you to use it almost like Spring Data Projections: https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features
Page<EntityDto> findAll(Pageable pageable);
The best part is, it will only fetch the state that is actually necessary!
With the Spring WebMvc integration you can even materialize the entity view like this:
#RequestMapping(path = "/my-endpoint", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<String> updateCat(#RequestBody EntityDto dto) {
myRepository.save(dto);
return ResponseEntity.ok(dto.getId().toString());
}
It will be persisted/updated just as you would expect it!

How to pass pageable for native query?

I was doing a project and there i had a requirement of using pageable object and recieved page object from JPA.
Does anyone have any idea on how to use this?
#Repository
public interface CustomerRepository extends JpaRepository<Customer,Long>{
#Query("SELECT * FROM WHERE name=?1 AND surname=?2 ", nativeQuery = true)
List<Customer> findAllByNameAndSurname(String name,String surname);
}
I want a page List for result fetch from this query.
Spring Data JPA and native queries with pagination is not supported in Spring. According to documentation , Spring Data JPA repositories can be used with native queries and pagination. But, in real life Spring Data JPA (1.10.2.RELEASE) requires some additional fix.
You have to use this if you want pagination support.
List<Customer> customers = customerRepository.findAllByNameAndSurname(name,username);
PagedListHolder<Customer> pages = new PagedListHolder(customers);
pages.setPage(currentPageNumber); //set current page number
pages.setPageSize(pageSize); // set the size of page
pages.getPageList(); // return the list of items(or in your case List<Customer> ) of current page
Try this:
#Repository
public interface CustomerRepository extends JpaRepository<Customer, Long> {
Page<Customer> findAllByNameEqualsAndSurnameEquals(String name, String surname, Pageable pageable);
}
I am pretty sure JpaRepository can handle your Pageable parameter.
Also, method name has to be as I mentioned as spring creates queries based on method name (uses reflection).
If you really need to execute NATIVE QUERY you will have to find other solution but I do not recommend the one provided by Dasari Swaroop Kumar as it just queries all objects from database and then kinda filters it in memory.
Also to that native query solution - you can extend your method definition to additional 2 parameters for page and pageSize and append them to your native query and leave repository to return plain List and then create PageImpl object in the layer that calls your CustomerRepository object.

How to retrieve only values of a single column in Crud Repository in Springboot from method Names without using #Query Annotation?

I need to retrieve distinct values of a particular column in CrudRepository in Springboot without using #Query annotation.
A single value is not possible but you could use interface-based projections:
For example if you need only the name of a table:
interface NameOnly {
String getName();
}
interface PersonRepository extends Repository<Person, UUID> {
Collection<NameOnly> findByLastname(String lastname);
}
Read more here:
https://docs.spring.io/spring-data/jpa/docs/2.1.4.RELEASE/reference/html/#projections

How to get the specific property value from .properties file in Spring Data Repository interface method #Query

I am able to get the property value in Spring classes like below:
#Value("${database.name}")
private String databaseName;
I have to execute a native query by joining different tables which are in different databases.
#Query(value="select t1.* FROM db1.table1 t1 INNER JOIN db2.table2 t2 ON t2.t1_id1 = t1.id1")
Instead of hard coding database names i.e., db1 and db2 here, I have to get them from properties file.
how to get the property value inside the #Query annotation in Spring Data JPA Repository ?
I don't know if it is possible, but if not, you can consider this approach:
Instead of using properties in Repository's #Query directly, you can use params in the query but when you call the actual method - you can provide values from .properties.
Imagine you have simple repository:
public interface UserRepository extends JpaRepository<User, Long> {
// query with param
#Query("select u from User u where u.lastname = :lastname")
User findByLastname(#Param("lastname") String lastname);
}
Then, let's say you have some Service or Controller where you need to use your Repository - you can inject properties there and pass them to your method:
#Service
public class UserService {
// this comes from .properties
#Value("${user.lastName}")
private String userLastName;
#Autowired
private UserRepository userRepository;
public User getUser() {
// you pass it as param to the repo method which
// injects it into query
return userRepository.findByLastname(userLastName);
}
}
This is just an example. But I believe it may be useful.
Happy hacking :)

SpringData findAll is processing all database tables and not the one requested

I am new to SpringData and I am not getting what is happening here. I have created an Interface that extends PagingAndSortingRepository and overrided the findAll() method like this:
#Override
#Query
List<MyEntity> findAll();
I am calling this method in my service, but it is making my app to throw an exception Caused by: java.lang.StackOverflowError because that method is reading through the entire database, not only from MyEntitytable in database. Any idea?
Apparently the problem is in the configuration of EclipseLink. In persistence.xml I added this row <shared-cache-mode>NONE</shared-cache-mode> and now it works as it should.
no need to override getall() method.in your service autowired that dao or repository class and using this you can directly call the findall() method.
in the case you want to write your custom method apart from what given by spring data jpa then we use the #Query to write custom query.
No Need to Override. What i have done is i have created a repository i.e
FavoriteRepository which is extending JpaRepository and i have mentioned the
dbmodel name (Favorite)
like this JpaRepository<Favorite, Long> // Here Favorite is my model name
and Long is the type of primary key mentioned in db model Favorite as #Id
#Repository
public interface FavoriteRepository extends JpaRepository<Favorite, Long>{
}
Now you can use method findOne or findAll. As these methods are present in
Jparepository.Hope so it will help
If you want to add new method then use #Query with JpQL
#Query(value = "select f from Favorite f where f.userId=:userId ")
public List<Favorite> getFavoritesForUser(#Param("userId") String userId);

Resources