Count all specific properties of entity JPA - java

I have question. I have 3 entities Book->Part->Page with relationships.
Book.java
#Entity
#Table(name = "Book")
public class Book{
#ID
#Column(name = "id")
private Long id;
#OneToMany
#JoinColumn(name="bookid", referencedColumnName="id")
private Set<Part> parts = new HashSet<Part>;
}
Part.java
#Entity
#Table(name = "Part")
public class Part{
#ID
#Column(name = "id")
private Long id;
#Column(name="bookid")
private Long bookid;
#ManyToMany
#JoinTable(name="partpage",
joinColumns = #JoinColumn(name = "id")
inverseJoinColumns = #JoinColumn(name = "pageid")
private Set<Page> pages = new HashSet<Page>;
}
Page.java
#Entity
#Table(name = "Page")
public class part{
#ID
#Column(name = "pageid")
private Long id;
#Column(name="color")
private String color;
#Column(name="type")
private String type;
}
I have query = "Select b FROM book b". This query returns all books with all relation parts and pages.
What I need.
I need count how many pages with color = green and type = comedy in each Book. Is it possible to do it in one query?
Thank you all.

Related

JPA : How to handle mapping with a table that has relationship with two other tables?

I have three tables, table A (product), table B (invoice) and table C (invoices_info) which contains two columns referencing invoice_id and product_id. How can i insert a new entry (a new invoice) while inserting the products to the appropriate table and inserting the invoice info to its table also ?
Here are the entity classes :
Product
#Entity
#Table(name = "product")
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name = "family_id")
private long familyId;
#Column(name = "product_name")
private String productName;
#Column(name = "product_category")
private String productCategory;
#Column(name = "product_quantity")
private int productQuantity;
//getters and setters
}
Invoice
#Entity
#Table(name = "invoice")
public class Invoice {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "invoice_id")
private Long id;
#Column(name = "provider_id")
private Long providerId;
#Column(name = "total")
private int invoiceTotal;
#Column(name = "date")
private Date invoiceDate;
//getters and setters
}
InvoiceInfo
#Entity
#Table(name = "invoice_info")
public class InvoiceInfo {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "item_id")
private long id;
#Column(name = "product_id")
private long productId;
#Column(name = "invoice_id")
private long invoiceId;
//getters and setters
}
InvoiceInfo should be join table, Define relationship on entities Product & Invoice using annotations #OneToMany, #ManyToOne based on your requirement.
You have to create relationships between your entities by using a set of annotations like: #ManyToOne, #OneToMany, #ManyToMany or #OneToOne... and other annotations if needed.
In your case I am not really sure you need an InvoiceInfo table, as the Invoice table can (or should) already contains the list of products.
I would suggest you the following relationships:
Product
#Entity
#Table(name = "product")
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name = "family_id")
private long familyId;
#Column(name = "product_name")
private String productName;
#Column(name = "product_category")
private String productCategory;
#Column(name = "product_quantity")
private int productQuantity;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "invoice_id", referencedColumnName = "id")
private Invoice invoice;
//getters and setters
}
Invoice
#Entity
#Table(name = "invoice")
public class Invoice {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "invoice_id")
private Long id;
#Column(name = "provider_id")
private Long providerId;
#Column(name = "total")
private int invoiceTotal;
#Column(name = "date")
private Date invoiceDate;
#OneToMany(mappedBy = "product")
private List<Product> products;
//getters and setters
}
As your table InvoiceInfo no longer exists, you just have to insert you data in two table like this:
Invoice invoice = invoiceRepository.save(invoice);
Product product = new Product();
// Set the other properties
product.setInvoice(invoice);
productRepository.save(product);

javax.persistence.EntityNotFoundException: Unable to find kg.library.spring.library_spring.entity.Author with id 10000001

I'm new to Spring and I'm probably making the dumbest mistake, but I can't solve this problem for more than 2 hours. According to the video tutorial, I did Pagination, I did it exactly like his, but he did not have relationships between entities. I think the error is in a one-to-one relationship between Author and Book entity. Can you please help?
I wanted to add pagination because I have more than a million records in my table, after adding pagination I got this error.
Book Entity:
#Entity
#Table(name = "books")
public class Book {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name = "title")
private String title;
#Column(name = "publishing_year")
private Integer publishingYear;
#Column(name = "sell_cost")
private BigDecimal sellCost;
#Column(name = "rent_cost")
private BigDecimal rentCost;
#Column(name = "amount")
private Integer amount;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "author_id")
private Author author;
//getter and setters
Author Entity:
#Entity
#Table(name = "author")
public class Author {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name = "fullname")
private String fullname;
#Column(name = "birthday")
private Date birthday;
#OneToOne(mappedBy = "author")
private Book book;
//getters and setters
BookServiceImpl class:
#Service
public class BookServiceImpl implements BookService
{
#Autowired
private BookRepository bookRepository;
#Override
public Page<Book> findPaginated(int pageN, int pageSize,String sortField,String sortDirection) {
Sort sort = sortDirection.equalsIgnoreCase(Sort.Direction.ASC.name()) ? Sort.by(sortField).ascending() :
Sort.by(sortField).descending();
Pageable pageable = PageRequest.of(pageN-1,pageSize,sort);
return bookRepository.findAll(pageable);
}
}
LibrarianController class:
#GetMapping("/books/{pageN}")
public String getAllBooks(#PathVariable (value = "pageN") int pageN,Model model,
#RequestParam("sortField") String sortField,
#RequestParam("sortDir") String sortDir){
int pageSize = 25;
Page<Book> page = bookService.findPaginated(pageN,pageSize,sortField,sortDir);
List<Book> books = page.getContent();
model.addAttribute("currentPage",pageN);
model.addAttribute("totalPages",page.getTotalPages());
model.addAttribute("totalItems", page.getTotalElements());
model.addAttribute("books",books);
model.addAttribute("sortField",sortField);
model.addAttribute("sortDir",sortDir);
model.addAttribute("reverseSortDir",sortDir.equals("asc") ? "desc" : "asc");
return "librarian/show-all-books";
}
It seems that you have a Book record that refers to an Author with id 10000001 that does not exit in Author table.
Try these changes. I hope that each book has only one author.
Book.java:
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "author_id")
private Author author;
Author.java:
#OneToMany(mappedBy = "author")
private List<Book> books=new ArrayList<>();

Accessing #JoinTable in many-to-many relationship in Springboot JPA

I've created an API that has actor, movie and category entities. Actor and movie are connected by many-to-many relationship that maps to a join table called movie_actor and category is connected with movie by one-to-many relationship.
I'm trying to write a native query that returns an integer that would represent the amount of movies from a specific category where specific actor has played so for example query would return 2 if actor played in 2 different sci-fi movies. I have no problem doing that from the database level where I can see the join table movie_actor but that table remains unaccessible in my api because it's not a separate entity. How can I create it that it automatically maps actor and movie ids as the movie_actor table ?
Here is an example code that works for me in the H2 Database:
SELECT COUNT(*) FROM MOVIE M JOIN MOVIE_ACTOR MA on M.MOVIE_ID = MA.MOVIE_ID WHERE ACTOR_ID = 1 AND CATEGORY_ID = 1
Here are my entities:
Actor:
#Entity
#Data
#Table(name = "actor")
#AllArgsConstructor
#NoArgsConstructor
public class Actor {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "actor_id")
private long actorId;
#Column(name = "name")
private String name;
#Column(name = "surname")
private String surname;
#Nullable
#ManyToMany(mappedBy = "actors", fetch = FetchType.EAGER)
#JsonBackReference
private List<Movie> movies = new ArrayList<>();
public Actor(String name, String surname){
this.name = name;
this.surname = surname;
}
}
Movie:
#Entity
#Data
#Table(name = "movie")
#AllArgsConstructor
#NoArgsConstructor
public class Movie {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "movie_id")
private long movieId;
#Column(name = "title")
private String title;
#ManyToMany
#JoinTable(
name = "movie_actor",
joinColumns = #JoinColumn(name = "movie_id"),
inverseJoinColumns = {#JoinColumn(name = "actor_id")}
)
#JsonManagedReference
private List<Actor> actors = new ArrayList<>();
#ManyToOne
#JoinColumn(name = "CATEGORY_ID")
#JsonManagedReference
private Category category;
}
So you have to make it accessible in your API. One option would be to map the intersection table movie_actor to the entity MovieActor and split ManyToMany relationship between Actor and Movie to OneToMany relationship with MovieActor, like that:
#Entity
#Data
#Table(name = "movie_actor")
#AllArgsConstructor
#NoArgsConstructor
public class MovieActor {
#EmbeddedId
private MovieActorId productOrderId = new MovieActorId();
#ManyToOne(cascade = CascadeType.ALL, optional = false)
#MapsId("movieId")
#JoinColumn(name = "product_id", nullable = false)
private Movie movie;
#ManyToOne(cascade = CascadeType.ALL, optional = false)
#MapsId("actorId")
#JoinColumn(name = "order_id", nullable = false)
private Actor actor;
public void addMovieActor(Movie aMovie, Actor aActor) {
movie = aMovie;
actor = aActor;
aMovie.getMovieActors().add(this);
aActor.getMovieActors().add(this);
}
}
#Embeddable
#Getter
#Setter
public class MovieActorId implements Serializable {
#Column(name = "movie_id")
private Long movieId;
#Column(name = "actor_id")
private Long actorId;
}
#Entity
#Data
#Table(name = "actor")
#AllArgsConstructor
#NoArgsConstructor
public class Actor {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "actor_id")
private long actorId;
#OneToMany(mappedBy = "actor")
private List<MovieActor> movieActors = new ArrayList<>();
}
#Entity
#Data
#Table(name = "movie")
#AllArgsConstructor
#NoArgsConstructor
public class Movie {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "movie_id")
private long movieId;
#OneToMany(mappedBy = "movie")
private List<MovieActor> movieActors = new ArrayList<>();
}
Now you can access the intersection table MovieActor inside the query. You can even add more columns to this table if you want.

Java JPA Realtions

I am doing an application where I need 2 entities: User and Car.
public class User{
private long id;
private String name;
}
public class Car{
private long id;
private User firstUser;
private User secondUser;
}
So my table cars_info info will contain
RENT(date), FIRST_USER(id), SECOND_USER(id)
How do I connect this using hibernate? I need unidirectional relation. I tried OneToOne, ManyToOne but neither of that works.
Check that you're properly naming the column on your CAR table vs the reference column on the USER table. Example below:
#Entity
#Table(name = "USER")
public class User {
#Id
#Column(name = "USER_ID")
private long id;
#Column(name = "NAME")
private String name;
}
#Entity
#Table(name = "CAR")
public class Car {
#Id
#Column(name = "CAR_ID")
private long id;
#ManyToOne
#JoinColumn(name = "FIRST_USER_ID", referencedColumnName = "USER_ID")
private User firstUser;
#ManyToOne
#JoinColumn(name = "SECOND_USER_ID", referencedColumnName = "USER_ID")
private User secondUser;
}

Jpa Criteria for ManyToMany and OneToOne relationships

I have 3 POJO classes - Link, LinkDetails and Tag.
The relationship between Link and LinkDetails - OneToOne, between LinkDetails and Tag - ManyToMany.
How to use Jpa Criteria, find a list of links with a specified tag name ?
#Entity
public class Link extends AbstractEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column
private String url;
#OneToOne(cascade = CascadeType.ALL)
#PrimaryKeyJoinColumn
private LinkDetails linkDetails;
}
#Entity
public class LinkDetails extends AbstractEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column
private String description;
#JoinTable(name = "link_details_2_tag", joinColumns = { #JoinColumn(name = "link_details_id")}, inverseJoinColumns = { #JoinColumn(name = "tag_id") })
#ManyToMany(targetEntity = Tag.class, fetch = FetchType.LAZY)
private Set<Tag> tags = new TreeSet<Tag>();
}
#Entity
public class Tag extends AbstractEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column
private String name;
}
#Override
public List<Link> getLinksByTag(String tag){
CriteriaBuilder cBuilder = getEntityManager().getCriteriaBuilder();
CriteriaQuery<Link> criteria = cBuilder.createQuery( Link.class );
Root<Link> linkRoot = criteria.from( Link.class );
Join<Link, LinkDetails> linkDetailsJoin = linkRoot.join(Link_.linkDetails);
Join<LinkDetails, Tag> tagJoin = linkDetailsJoin.join(LinkDetails_.tags);
criteria.select(linkRoot);
criteria.where(cBuilder.equal(tagJoin.get(Tag_.name), tag));
TypedQuery<Link> query = getEntityManager().createQuery(criteria);
return query.getResultList();
}

Categories