Spring data make query to override all object fields - java

I'm using Spring data and I have to change all fields of one object.
Usually I use for example:
#Modifying
#Query("UPDATE Car u SET u.datatable= ?2 WHERE u.idCar = ?1")
void setDatatable(int idCar, String datatable);
in my repository class. Now I should use
#Modifying
#Query("UPDATE OilSample u SET all fields WHERE u.idOilSample = oilSampleMap.idOilSample")
void modify(OilSampleMap oilSampleMap);
but idOilSample and all my fields are in OilSampleMap instance (it has all the OilSample fields). Is it possible to use #Query annotation or Query Methods? Thanks

Related

How to pass path variable to JPA repository from controller

How to pass path variable to JPA repository from controller.
I have a controller here and from the front End I am getting one varaible.
here is my controller :
#GetMapping("/getTransictionsAndInstruments/{id}")
public List<TransictionProjection> getTransitionInstrument(#PathVariable Long id){
return transictionrepository.getTransictionsAndInstruments();
}
Based on this id i want some alteration in my reult. I ahve already have on query and want to use this id in repo. so how to pass that in repo.
#Repository
public interface TransictionRepository extends JpaRepository<Transictions, Long>{
#Query(value = "SELECT transiction.user_id, transiction.quantity, transiction.instrument_name, transiction.Price, instrument.LTP, instrument.jo_caps FROM instrument INNER JOIN transiction ON instrument.instrument = transiction.instrument_name where transiction.User= id", nativeQuery = true)
List<TransictionProjection> getTransictionsAndInstruments();
}
I want to include this line in my query where transiction.User= id
Any help here that how to achive this.
I think this can be achieved by following:
Adding :id in your native query and passing id in function.
#Query(value = "SELECT transiction.user_id, transiction.quantity, transiction.instrument_name,
transiction.Price, instrument.LTP, instrument.jo_caps FROM instrument INNER JOIN transiction ON instrument.instrument = transiction.instrument_name
where transiction.User= :id", nativeQuery = true)
List<TransictionProjection> getTransictionsAndInstruments(Long id);

How to pass complete query as String in repository method as argument and use with the #Query Annotation?

I prepared a query in serviceImplementation ,After that I passed this query as method argument of
presentDaySummarySmscWise(String finalQuery) Repository method.
In Repository Interface ,I passed this query with #Query Annotaion like shown in code.
strong text
//ServiceImplementation class
#Service
public class ErrorCodeServiceImpl implements ErrorCodeService {
#Autowired
ErrorCodeRepository errorCodeRepo;
#Override
public List<Object[]> errorCodeDefaultSummary() {
String finalQuery="select smsc,vf_reason_code from reason_code_report where
log_date='2021-05-27'";
List<Object[]> result = errorCodeRepo.presentDaySummarySmscWise(finalQuery);
return result;
}
strong text
//Repository
#Repository
public interface ErrorCodeRepository extends JpaRepository<ErrorCodeReportEntity, ErrorCodeReportKeys>{
#Query(value=":query",nativeQuery=true)
List<Object[]> presentDaySummarySmscWise(String query);
}
You cannot replace arbitrary fragments of the query using a query parameter. Only very specific sections of the query allow parameters.
If you need dynamic queries, Specifications or QueryDSL is what you want.
I believe you need to add #Param("query") into your argument in the repository.
List<Object[]> presentDaySummarySmscWise(#Param("query") String query);

Spring Data Elasticsearch Class Cast exception on Named Query

I'm getting the following exception when trying to use a named query with Spring Data Elasticsearch.
ClassCastException: org.springframework.data.elasticsearch.core.aggregation.impl.AggregatedPageImpl cannot be cast to org.springframework.data.elasticsearch.core.SearchPage
The query I'm trying to make is:
public interface PlayerRepository extends ElasticsearchRepository<PlayerEntity, String> {
#Query("{\"bool\":{\"must\":[{\"terms\":{\"playerNumber.keyword\": ?0}}]}}")
SearchPage<PlayerEntity> fetchPlayers(JSONArray playerNumbers, Pageable pageable);
}
If I do not use the #Query annotation and instead let Spring derive the query from the method name like so:
SearchPage<PlayerEntity> findPlayerEntityByPlayerNumberIn(List<String> playerNumbers, Pageable pageable);
It works as expected. However, the PlayerNumber field is a #MultiField that supports the the field types of Text and Keyword like so:
#Document(indexName = "#{#playersIndexName}")
public class PlayerEntity {
#MultiField(
mainField = #Field(type = Text, name = "playerNumber"),
otherFields = {#InnerField(suffix = "keyword", type = Keyword)})
private String playerNumber;
...
}
And I need to use the keyword mapping here for the query and not the text mapping. As far as I can tell, Spring Data Elasticsearch cannot derive queries from method names on InnerField, which is why I went with the named query approach. But it seems like the using the declared query approach, detailed here, only supports a subset of return types as detailed here
In addition, I need to use the SearchPage return type as well, because there is metadata there that I need to make decisions on.
So I guess there are a couple of questions that come out of this:
Is it possible to use InnerFields in derived query methods? i.e. something like SearchPage<PlayerEntity> findPlayerEntityByPlayerNumber_KeywordIn(List<String> playerNumbers, Pageable pageable);
Is it possible for a named query to return a SearchPage? I think this might be possible with a custom Repository implementation, but if I could get either approach above to work that would be ideal.
Thanks for any help!!
spring-data-elasticsearch version: 4.0.3.RELEASE
spring-boot-starter-parent version: 2.3.3.RELEASE
elasticsearch version: 7.11.1
To answer your second question (Is it possible for a named query to return a SearchPage?): This is a bug that it does not work with #Query annotated methods. I fixed that yesterday for the main, 4.2.x, 4.1.x and 4.0.x branches so it will work when the next service releases are out.
To answer the first one, I will need to do some research and tests before I can say anything about that - it would be great if it would work. I think I' can give more information later this weekend.
Edit/Addition:
The query derivation from the method name is based on the properties of the Java class and is done in the Spring Data base which knows nothing about these inner fields that only exist in Elasticsearch.
But you can use the following custom repository fragment:
public interface CustomPlayerRepository {
SearchPage<PlayerEntity> findPlayerEntityByPlayerNumberKeywordIn(List<String> playerNumbers, Pageable pageable);
}
public class CustomPlayerRepositoryImpl implements CustomPlayerRepository {
private final ElasticsearchOperations operations;
public CustomPlayerRepositoryImpl(ElasticsearchOperations operations) {
this.operations = operations;
}
#Override
public SearchPage<PlayerEntity> findPlayerEntityByPlayerNumberKeywordIn(
List<String> playerNumbers, Pageable pageable) {
var criteriaQuery = new CriteriaQuery(new Criteria("playerNumber.keyword").in(playerNumbers), pageable);
var searchHits = operations.search(criteriaQuery, PlayerEntity.class);
return SearchHitSupport.searchPageFor(searchHits, pageable);
}
}

Spring Data JPA - Creating custom query method generator

In Spring Data JPA we can define a repository interface extending Repository and write a custom method.
If this method follows special syntax, Spring Data will generate the method body automatically.
For example (from the documentation):
interface PersonRepository extends Repository<Person, Long> {
List<Person> findByLastname(String lastname);
}
Is there a way to customize the method generation code to introduce new keywords into the syntax?
For example:
Person findExactlyOneById(Long id);
This method would either return the entity or throw a custom exception.
I know I can customize specific repositories as well as the base repository and achieve the effect from the above example, but I'm specifically asking for the automatic method of body generation.
Is there an extension point designed in the framework? Or is the only option to change the source code?
In your case, you can always use CrudRepository.findById(Long id) or JpaRepository.getOne(Long id).
I would suggest inheriting from the JpaRepository class because all types of repositories are included.
You can set nativeQuery = true in the #Query annotation from a Repository class like this:
public static final String FIND_PROJECTS = "SELECT projectId, projectName FROM projects";
#Query(value = FIND_PROJECTS, nativeQuery = true)
public List<Object[]> findProjects();
It's probably worth looking at the Spring data docs as well.
Some more example
1.
public interface UserRepository extends JpaRepository<User, Long> {
#Query(value = "SELECT * FROM USERS WHERE EMAIL_ADDRESS = ?1", nativeQuery = true)
User findByEmailAddress(String emailAddress);
}

Spring Data JPA how to pass a variable by using #repository

Thank U, guys! I have found the solution:
#Repository
public interface BookRepository extends JpaRepository<Book, Integer>{
#Query(value = "select * from Book where find_in_set(:market,market)", nativeQuery = true)
public List<Book> findBooksByMarcket(#Param("market") String market);
}
Original question
I'm using the #Query annotation to create queries by using the JPA query language and to bind these queries directly to the methods of my repository interface.
My database is created correctly and I'm successful to create some queries except this one:
#Repository
public interface BookRepository extends JpaRepository<Book, Integer>{
#Query("select b from Book b where find_in_set(:market,b.market)")
public List<Book> findBooksByMarcket(#Param("market") String market);
}
I can get the correct result by using the find_in_set function when I check it though MySql. But I cannot reach to pass a variable in java. I have searched though the internet but I cannot find the correct format for it.
please help and thank you guys!
A quick solution is to transform the JPQL query to a native query (by setting the nativeQuery flag to true):
#Query(value = "select * from Book b where find_in_set(:market,b.market)", nativeQuery = true)
public List<Book> findBooksByMarcket(#Param("market") String market);
If you have a custom MySQL function and want to utilize it in a JPA repository, please take a look at tip 1
There is another way to do it using CriteriaBuilder (I used this mechanism along with JPA specification): tip 2
Key words for your search: custom db function, JPA specification, CriteriaBuilder, Criteria
Try this
#Repository
public interface BookRepository extends JpaRepository<Book, Integer>{
#Query("select b from Book b where find_in_set(?1,b.market)")
public List<Book> findBooksByMarcket(String market);
}

Categories