Fetch data by id AND String from single database - java

I am totally new to Hibernate, Spring and postgres database world. There may be difference in "terms" using to describe.
So issue is, i want to fetch a data where it matches given "id" AND "string" using hibernate, JPA annotations in spring boot.
I know basic like repository.findOne(id) but i am not aware of how to get data with two parameters.
I guess i need something like, i am not sure as i am new to db world
SELECT *
FROM student
WHERE type='commerce'
AND id='1'"
I thank you in advance and tutorials to study further is most welcome.

Spring boot provides for you some automatic repositories, so you just create a interface that extends "JpaRepository" and then, create methods with a natural language.
Something like:
#Repository
public interface StudentRepository extends JpaRepository<Student, Long> {
public List<Student> findByIdAndType(Long id, String type);
}
Later on, let's say you want to use this class:
#Autowired
private StudentRepository studentRepository;
public void doSomething() {
List<Student> students = studentRepository.findByIdAndType(1, "commerce");
}
And no, there is no need to provide an implementation to the interface "StudentRepository", as spring data will provide it to you in behind the scenes.
More information on how this works, you can find on proper spring-data documentarion
Cheers, Nikolas

Related

How to make a custom method in Spring Data JPA

Currently, I'm learning about Spring Data JPA, and I found that I need to create a custom interface to make a custom methods. I wonder if someone can explain to me why this is so. Let's say I have entity User with fields: userId and name. Also, I have UserRepository:
public interface UserRepository extends JpaRepository<User, Long> {...}
I found that I need to make new interface - UserRepositoryCustom where I should make custom abstract methods. Also, after that, I found that I need to make class UserRepositoryImpl which implements UserRepositoryCustom. Let's take a look at the code I made:
#Repository
public class UserRepositoryImpl implements UserRepositoryCustom{
#PersistenceContext
private EntityManager entityManager;
#Override
public List<User> findUserByName(String name) {
Query query = entityManager.createNativeQuery("SELECT em.* FROM User em " +
"WHERE em.name = ?1", User.class);
query.setParameter(1, name);
return query.getResultList();
}
}
Can you please explain why I need UserRepositoryCustom and UserRepositoryImpl in foreground, And why do I need EntityManager and #PersistenceContext above it? Every piece of information is of great importance to me, because that way I will be able to extract what is most important for me, which is to understand.
I found this code, which is working fine, online, but I need to understand it.
You don't need to do this. The direct equivalent would be a method in your UserRepository interface defined as List<User> findByName(String name). You can also use JPA named queries, the #Query annotation, etc.
The usage of additional interfaces and implementation classes is intended for advanced use cases that are not (easily) possible in the queries Spring Data JPA generates for you based on method names, annotations, etc. It is not intended for easy use cases like the query you show.
And the reason why, is because that is how Spring Data JPA is designed. I highly recommend you read the full Spring Data JPA documentation. You'll notice that the solution in your question is just a minor part of the documentation, which makes clear that this is an escape hatch, not the primary way of using Spring Data JPA.

Spring data repositories - parameter what to retrieve all records?

#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

Use Spring Data JPA, QueryDSL to update a bunch of records

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 :)

Extend spring data's default syntax

In my current project almost every entity has a field recordStatus which can have 2 values:
A for Active
D for Deleted
In spring data one can normally use:
repository.findByLastName(lastName)
but with the current data model we have to remember about the active part in every repository call, eg.
repository.findByLastNameAndRecordStatus(lastName, A)
The question is: is there any way to extend spring data in such a way it would be able to recognize the following method:
repository.findActiveByLastName(lastName)
and append the
recordStatus = 'A'
automatically?
Spring Data JPA provides 2 additional options for you dealing with circumstances that their DSL can't handle by default.
The first solution is custom queries with an #Query annotation
#Query("select s from MyTable s where s.recordStatus like 'A%'")
public MyObect findActiveByLastName(String lastName);
The second solution is to add a completely custom method the "Old Fashion Way" You can create a new class setup like: MyRepositoryImpl The Impl is important as it is How spring knows to find your new method (Note: you can avoid this, but you will have to manually link things the docs can help you with that)
//Implementation
public class MyRepositoryImpl implements MyCustomMethodInterface {
#PersistenceContext
EntityManager em;
public Object myCustomJPAMethod() {
//TODO custom JPA work similar to this
String myQuery = "TODO";
return em.createQuery(myQuery).execute();
}
}
//Interface
public interface MyCustomMethodInterface {
public Object myCustomJPAMethod();
}
//For clarity update your JPA repository as well so people see your custom work
public interface MySuperEpicRepository extends JPARepository<Object, String>, MyCustomMethodInterface {
}
These are just some quick samples so feel free to go read their Spring Data JPA docs if you would like to get a bit more custom with it.
http://docs.spring.io/spring-data/jpa/docs/current/reference/html/
Finally just a quick note. Technically this isn't a built in feature from Spring Data JPA, but you can also use Predicates. I will link you to a blog on this one since I am not overly familiar on this approach.
https://spring.io/blog/2011/04/26/advanced-spring-data-jpa-specifications-and-querydsl/
You can use Spring Data's Specifications. Take a look at this article.
If you create a 'Base'-specification with the recordStatus filter, and deriving all other specifications form this one.
Of course, everybody in your team should use the specifactions api, and not the default spring data api.
I am not sure you can extend the syntax unless you override the base class (SimpleReactiveMongoRepository; this is for reactive mongo but you can find the class for your DB type), what I can suggest you is to extend the base methods and then make your method be aware of what condition you want to execute. If you check this post you get the idea that I did for the patch operation for all entities.
https://medium.com/#ghahremani/extending-default-spring-data-repository-methods-patch-example-a23c07c35bf9

Generic Dao and service Layer

I am going to design a DAO layer for my application. My focus is that Services just calls DAO which is independent of underlaying implementation.
public interface GenericSearchDao{
List getAll();
List getByQuery(String query);
}
public class UserJdbcSearch implements GenericSearchDao{
public List getAll(){
// Get all users;
}
List getByQuery(String query){
// Get users by query;
}
}
public class UserFileSystemSearch implements GenericSearchDao{
public List getAll(){
// Get all users from file system;
}
List getByQuery(String query){
// Get users by query[this leads to invalid operation];
}
}
public userService {
private GenericSearchDao dao = new UserFileSystemSearch();
public List getUsers(){
rturn dao.getAll();
}
public List getByQuery(String query){
return dao.getByQuery(query);
}
}
Help Required:
What should I do to get rid from 'getByQuery(query)' specific implementaions because datastore can be RDBMS, filesystem, FTP etc.
How should I design my Dao layer generically?
If any one says "remove the getByQuery() from GenericSearchDao" then what should i do in the case where i need data specific to business operation for eg : user with roles , user with products etc..
What should I do to get rid from 'getByQuery(query)' specific implementaions because datastore can be RDBMS, filesystem, FTP etc.
You don't, you just need to provide "generic" query, for instance "name = a" may perform a query in a databae, or look for a file named "a" or pretty much anything else.
What information do you plan to pass in the "query" parameter ? SQL ? I'd replace the String parameter with something business-specific, maybe a small class wiht fields like "name", "surname", etc. The underlying implementation will transform it into SQL, or remote service calls, or other implementation-specific magic.
You may find this approach useful http://www.bejug.org/confluenceBeJUG/display/BeJUG/Generic+DAO+example
For specific impl just throw "UnsupportedOperationException". Good Generic dao implementation can be found here http://code.google.com/p/hibernate-generic-dao/ - I also could adjust the source code to work with hibernate 4 & spring 3
Hey, check this site DAO Implementation. There are some DAO implementations with different Design patterns. I think DAO with Abstact factory would be suitable for you.

Categories

Resources