I am trying to display a list of books by category.
Category.java
public enum Category {
NEW,
CLASSIC,
STANDARD;
}
BookDto.java
public class BookDto {
private Long id;
private String title;
private String author;
private String publisher;
private Category category;
private int totalCount;
}
RentController.java
#GetMapping("/booksCategory")
public List<BookDto> getBookByCategory(#RequestParam Category category) {
return rentService.getBookByCategory(category);
}
RentService.java
public List<BookDto> getBookByCategory(Category category) {
List<Book> book = bookRepository.findAllBookByCategory(category);
return mapBookListToBooDtoList(book);
}
BookRepository.java
public interface BookRepository extends JpaRepository<Book, Long> {
#Query("select count(b) from Book b")
List<Book> findAllBookByCategory(Category category);
}
From code above I am getting following error:
Required Category parameter 'category' is not present
If you check your query, you see that the parameter category is not used.
Also the query returns count(b) instead a books as required by the return type.
For simple queries you can omit the explicit query:
public interface BookRepository extends JpaRepository<Book, Long> {
List<Book> findByCategory(Category category);
}
Also make sure you actually pass a category as a query parameter to the HTTP request when calling your service, e.g.: GET https://my-service-url/booksCategory?category=CLASSIC
Related
I want to find a Type document by the code of job and by the list of code of category, i tried the below query but it didn't work
#Document
public class Type {
#Id
private String id;
#DBRef
private Job job;
#DBRef
private List<Category> categories;
}
public class Job {
#Id
private String id;
private String code;
}
public class Category {
#Id
private String id;
private String code;
}
public interface TypeRepository extends MongoRepository<Type, String> {
#Query("{ 'job.code': ?0, 'category.code': { $in: ?1 }}")
Type findByJobAndCategoriesCode(String codeJob, List<String> codeCategories);
}
try using this one
public interface TypeRepository extends MongoRepository<Type, String> {
Type findOneByJobCodeAndCategoriesCodeIn(String codeJob, List<String> codeCategories);
}
public interface LmsRepository extends CrudRepository
I have no findOne method for getting single count so when i using findById I got this exception."Property [id] not found on type [java.util.Optional]" How can i solve this trouble ?
This is my CrudRepo
#Repository
public interface LmsRepository extends CrudRepository<Book, Long> {
}
Entity File
#Entity(name="lms_tbl")
public class Book {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#Column(name="book_name")
private String bookName;
private String author;
#Column(name="purchase_date")
#Temporal(TemporalType.DATE)
private Date purchaseDate;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
and other....
Service File
#Service
public class LmsService {
#Autowired
private LmsRepository lmsRepository;
public Collection<Book> findAllBooks(){
ArrayList<Book> books = new ArrayList<Book>();
for (Book book : lmsRepository.findAll()) {
books.add(book);
}
return books;
}
public void deleteBook(long id) {
lmsRepository.deleteById(id);
}
public Optional<Book> findById(Long id) {
return lmsRepository.findById(id);
}
}
Controller File
#Controller
public class MainController {
#Autowired
private LmsService lmsService;
#GetMapping("/")
public String index(HttpServletRequest req) {
req.setAttribute("books", lmsService.findAllBooks());
req.setAttribute("mode","BOOK_VIEW");
return "index";
}
#GetMapping("/updateBook")
public String index(#RequestParam Long id,HttpServletRequest req) {
req.setAttribute("book", lmsService.findById(id));
req.setAttribute("mode","BOOK_EDIT");
return "index";
}
}
I tried add new method in CrudRepo but it doesnt work.
In your service class change this
public Optional<Book> findById(Long id) {
return lmsRepository.findById(id);
}
to this
public Book findById(Long id) {
return lmsRepository.findById(id).get();
}
Explanation: Optional is a wrapper class which may or may not contain a non-null value. You get that error because you are trying to insert Optional in the model, not Book. As Optional does not contain any id field, you get the error. Optional is used for having defalut values of throwing exception when you have a null object where you do not expect it to be null. You can create for example an automatic exception throwing in case of null optional. For example, you can upgrade your service in this way:
public Book findById(Long id) {
return lmsRepository.findById(id).orElseThrow(RuntimeException::new);
}
This will throw a RuntimeException any time Book is null inside the Optional, or will give you back the value of the Book class.
A more elegant solution is the following:
public Book findById(Long id) {
return lmsRepository.findById(id).orElseThrow(NotFoundException::new);
}
having:
#ResponseStatus(HttpStatus.NOT_FOUND)
public class NotFoundException extends RuntimeException{
}
In this way when the optional contains a Book, that is returned back to the controller and inserted in model. If the Optional contains a null value then NotFoundException will be thrown, it does not need to be catched, and will be mappet to 404 HTTP error.
You can create own methods in the repository.
LmsRepository<CustomClass> extends CrudRepository<CustomClass> {
Optional<CustomClass> findById(int id);
}
in your entity you declare #Id on id, so findById follow on this (primary key) datatype, id of the entity the repository manages.
Simply put .get() after lmsRepository.findById(id).get();
.get() parses and will return the [object of lms] caught from the database
No need to override, implement and et cetera.
You can add a method in your interface
#Repository
public interface LmsRepository extends CrudRepository<Book, Long> {
Optional<Book> findById(Long id);
}
Is there a way to write and register a TupleConverter converter in Spring Data? I'm getting this exception when I have an #Query annotation in the Repository interface and asking for Projection.
The Interface:
public interface ProjectRepository extends JpaRepository<Project, Integer> {
#Query("select p.projectId, p.projectName, p.techstack from Project p")
public List<ProjectItem> findAllForTest();
}
The DTO:
public class ProjectItem {
private final Integer projectId;
private final String projectName;
private final String techstack;
#JsonCreator
public ProjectItem(
#JsonProperty("projectId") Integer projectId,
#JsonProperty("projectName") String projectName,
#JsonProperty("techstack") String techstack
) {
this.projectId = projectId;
this.projectName = projectName;
this.techstack = techstack;
}
public Integer getProjectId() {
return projectId;
}
public String getProjectName() {
return projectName;
}
public String getTechstack() {
return techstack;
}
}
The exception
No converter found capable of converting from type [org.springframework.data.jpa.repository.query.AbstractJpaQuery$TupleConverter$TupleBackedMap] to type [project.item.ProjectItem]] with root cause
Use a JPQL Constructor Expression:
#Query("select new com.company.path.to.ProjectItem(p.projectId, p.projectName, p.techstack) from Project p")
You're close. If you just want a DTO with a few of the items from the original item, just use the interface projection technique with methods having the same signatures as the Project class method items you want:
public interface ProjectTestSummary {
public Integer getProjectId();
public String getProjectName();
public String getTechstack();
}
And in your DAO:
public interface ProjectRepository extends JpaRepository<Project, Integer> {
public List<ProjectTestSummary> findAllProjectedBy();
}
JAVA SPRING :I am exploring JPA and am not sure of optimized way to design db and using save() of repository to save entity data right away into DB. Specifically, I have a basic class viz. Movie -
package com.kurshit.moviesmgr.vo;
import java.util.List;
public class Movie {
long movieId;
String title;
String yearOfRelease;
List<String> genere;
public Movie(long movieId, String title, String yearOfRelease, List<String> genere) {
super();
this.movieId = movieId;
this.title = title;
this.yearOfRelease = yearOfRelease;
this.genere = genere;
}
public Movie() {
// TODO Auto-generated constructor stub
}
public long getMovieId() {
return movieId;
}
public void setMovieId(long movieId) {
this.movieId = movieId;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getYearOfRelease() {
return yearOfRelease;
}
public void setYearOfRelease(String yearOfRelease) {
this.yearOfRelease = yearOfRelease;
}
public List<String> getGenere() {
return genere;
}
public void setGenere(List<String> genere) {
this.genere = genere;
}
}
Each movie has list of Genere - List- it falls under, like - Action, Comedy, etc.
I am trying to create an interface that extends JpaRepository and use the inbuilt save method to save the Movie Data into DB.
I am not sure about how I should design my DB - As in, Questions like -
1. Shall I create two different tables for Movie and Genere wherein Movie table references to Genere ?
2. Shall I create just onw table and store all Genere's list as a single CSV in one column ?
3. Can I use repository's save() right away to save and map this data into respective tables.
Would really appreciate if someone can share any sources or sample code to refer or can offer any help.
Thanks much!
First of all, you should search look up #Entity annotation so that you can tell your ORM to create the necesary table for that entity.
Secondly, you need to ask yourself, how this application will work. It would be best in my opinion to create a genre entity as well, linked to Movie through a #ManyToMany relationship.
Try looking over the simple entity example here
https://spring.io/guides/gs/accessing-data-jpa/
First variant - with 'genre' as enum (if your genre is a fixed list):
#Data // it's Lombok annotation: https://projectlombok.org/features/Data
#NoArgsConstructor
#Entity
public class Movie implements Serializable {
#Id #GeneratedValue
private Integer id;
private String title;
private Integer yearOfRelease;
#ElementCollection
#Enumerated(EnumType.STRING)
#Column(name = "genre")
private List<Genre> genres;
public Movie(String title, Integer yearOfRelease, List<Genre> genres) {
this.title = title;
this.yearOfRelease = yearOfRelease;
this.genres = genres;
}
}
public enum Genre {
ACTION, COMEDY, ...;
}
public interface MovieRepo extends JpaRepository<Movie, Integer> {
}
In this case you create your movie like this:
Movie movie = new Movie("Title", 2000, Arrays.asList(ACTION, COMEDY));
movieRepo.save(movie);
Second variant - 'genre' as independent entity:
#Data
#NoArgsConstructor
#Entity
public class Movie implements Serializable {
// the same as previous one...
#ManyToMany
private List<Genre> genres;
}
#Data
#NoArgsConstructor
#Entity
public class Genre implements Serializable {
#Id private String name;
public Genre(String name) {
this.name = name
}
}
public interface MovieRepo extends JpaRepository<Movie, Integer> {
}
public interface GenreRepo extends JpaRepository<Genre, String> {
}
In this case you first create genres:
List<Genre> genres = genreRepo.saveAll(Arrays.asList(
new Genre("Action"),
new Genre("Comedy"),
));
Then create movie:
Movie movie = new Movie("Title", 2000, genres);
movieRepo.save(movie);
More info to read: Hibernate ORM User Guide - Collections
That is the JPA entity MyEntity.
Entity
class MyEntity{
private Integer id;
private Date date;
private Double montant;
#ManyToOne(fetch = FetchType.LAZY)
private User creator;
}
class User {
private Integer id;
private String name;
private String image;
private Integer age;
private String anotherField;
}
I would like to retrieve a list of MyEntity with some attributes of its creator (just the id, the name and its image).
So I created a Projection interface.
interface Projection{
public Integer getId();
public Date getDate();
public Double getMontant();
public User getCreator();
interface User {
public Integer getId();
public String getName();
public String getImage();
}
}
here JPA repository implementation :
public interface CommandeRepository extends JpaRepository<EbCommande, Integer> {
<T> Collection<T> findById(Integer id, Class<T> type);
<T> Collection<T> findByCreator(User client, Class<T> type);
}
The first query works as I hope.
On the other hand with the second, when I loop on the list of MyEntity returned, each access to the User attribute triggers a request to the database fetching all the attributes of the User.
I do not understand how JPA projections work anymore.
Help please!