How to create join table with extra column with JPA annotations? - spring-boot

I need for a project to join 2 SQL tables implemented like this :
I know that I'm not supposed to implement the table IngredientList as an object cause it's only here for SQL structure.
My code goes like this :
#Entity
#Table(name="recipe")
public class Recipe {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="id_recipe")
private Long id;
#OneToMany
#JoinTable(name="liste_ingredients", joinColumns = #JoinColumn(name = "id_recette",
referencedColumnName = "id_recette"),
inverseJoinColumns = #JoinColumn(name = "id_ingredient",
referencedColumnName = "id_ingredient"))
List<Ingredient> ingredients;
/* Getter/Setter/Constructor */
}
Which is the classic way but with that I lose the Quantity attribute that I want to associate with ingredient. And I don't get how I can work around this without creating an object IngredientList.
Thanks in advance.

Nevermind that I got my answer gonna edit it soon with code, for anyone with the same question.

Related

ManyToMany how to remove child from parent list

How to remove object from list without removing that parent object in many to many relationship?
I have ticketEntity with set of offenceEntity:
public class TicketEntity {
#Id
private String id;
#ManyToMany
#JoinTable(
name = "offences_in_tickets",
joinColumns = #JoinColumn(name = "ticket_id"),
inverseJoinColumns = #JoinColumn(name = "offence_id"))
private Set<OffenceEntity> offences;
}
and OffenceEntity with set of TicketEntity:
public class OffenceEntity {
#Id
#Column(name="id")
private String id;
private String name;
#ManyToMany(mappedBy="offences", cascade = CascadeType.ALL)
private Set<TicketEntity> tickets;
}
Should I change cascade type? Now when I remove one of OffenceEntity from database I am removing TicketEntity too, but I would like to delete only Offence.
I don't know what "parent" or "child" is, or what you mean by "removing from list", as there is no list in your examples. If you want an answer to your questions, please invest more time in writing up a proper question and try to re-read the question with the mindset of someone who doesn't work on this problem. Maybe ask a colleague if the question is immediately understandable before posting this.
Having said that, I can only assume that "parent" refers to TicketEntity and "child" refers to OffenceEntity.
So if you want to remove the many-to-many relationship between two such objects, you simply have to load the TicketEntity and remove the respective OffenceEntity from the offences set e.g. like this:
entityManager.find(TicketEntity.class, ticketId)
.getOffences()
.remove(
entityManager.find(OffenceEntity.class, offenceId)
);

#Batchsize annotation not working for OneToMany

I have following classes and on annotating #BatchSize annotation it is not working and I am getting n+1 select query.
Class Shipment{
#OneToMany(fetch = FetchType.LAZY, mappedBy = order.shipment, cascade = CascadeType.ALL,
orphanRemoval = true)
#BatchSize(size=20)
Set<Orders> orders = new Hashset(); <---- Batch size annotation not working
}
Order.class
class Order{
#ToString.Exclude
#ManyToOne
#JoinColumn(name = "item_fk")
Item item;
#ToString.Exclude
#ManyToOne
#JoinColumn(name = "shipment_fk")
Shipment shipment; }
Item.class
class Item{
String id;
String name;
}
What is mistake in implementation that i am getting n+1 queries?
Try to use List<Orders> instead of Set<Orders>.
Please note as it's mentioned in the documentation:
However, although #BatchSize is better than running into an N+1 query issue, most of the time, a DTO projection or a JOIN FETCH is a much better alternative since it allows you to fetch all the required data with a single query.
Your N + 1 query issue is due to the fact that you do eager fetching of Item in Order. Change to LAZY there and you should be good to go.

In many to many get only id instead of the whole object

public class Role {
#ManyToMany
#JoinTable(name = "user_to_role",
joinColumns = #JoinColumn(name = "role_id"),
inverseJoinColumns = #JoinColumn(name = "user_id",referencedColumnName = "id"))
private Set<User> users;
}
public class User {
#ManyToMany
#JoinTable(name = "user_to_role",
joinColumns = #JoinColumn(name = "user_id"),
inverseJoinColumns = #JoinColumn(name = "role_id"))
private Set<Role> roles;
}
I have a many to many relationship between the two classes. When calling role.getUsers(), I want to get only the user ids, the rest of the fields should be ignored, since there will be a lot of data and I don't want to load everything, How can I achieve this?
A straightforward way to do it would be to use a Criteria query, but to use it inside an Entity, you'd have to inject an EntityManager there, which is considered a bad practice. A better solution would be to create this query in a Service.
But if you still want to do it, then your getUsers method would look something like this:
public List<User> getUsers() {
Criteria cr = entityManager.createCriteria(User.class)
.setProjection(Projections.projectionList()
.add(Projections.property("id"), "id")
.setResultTransformer(Transformers.aliasToBean(User.class));
List<User> list = cr.list();
return list;
}
If you want to restrict your list, just use a Restrictions, like so: criteria.add(Restrictions.eq("id", yourRestrictedId))
Since you have mapped the entities User and Role using #ManyToMany relationship, you need to create a DAO/Service class to implement the business logic to filter only userIds and return the same.
This cannot be handled in your Model\Entity classes as it will defy the whole concept of Object-Relational mapping.
I can create the business logic using DAO for your example if you want but you will get 10's of blogs achieving the same.
For your reference,you can check my sample project here.

Sort entities by count of *-to-Many association in Spring Data JPA

I'm developing a REST API (blog) using Spring Boot running with MySQL database.
Simply, I need to sort Article by the number of likes it has. The information about number of likes is stored in article_likes table which acts like association between Article and User (who liked the article).
#Entity
class Article {
#ManyToMany
#JoinTable(
name = "article_likes",
joinColumns = #JoinColumn(name = "article_id", referencedColumnName = "id"),
inverseJoinColumns = #JoinColumn(name = "user_id", referencedColumnName = "id")
)
Set<User> likedBy = new HashSet<>();
#Column(name = "created")
#CreationTimeStamp
LocalDateTime added;
}
I'm having a service which returns a Page of Article for given Pageable (comes from frontend):
Page<Article> getArticles(Pageable pageable);
In frontend, when I'm showing list/page of articles, I'm using following call to get the last (newest) 5 articles.
localhost:8080/api/articles?size=5&sort=added,desc
I want to do the same with but with number of likes, something like this:
localhost:8080/api/articles?size=5&sort=likedBy,desc
I've tried following variations without the success.
sort=likedBy.size
sort=likedBy.count
sort=likedBy.length
with following error:
No property * found for type User! Traversed path: Article.likedBy.",
Is something like this possible? If not, is there a way to store just the read-only count of likes in Article (as attribute) instead? Because in this particular situation its not important who liked it, but only the count.
class Article {
#Transient
#ManyToMany
???
long likes;
}

Join table data gets deleted when updating an entity in ManyToMany Relationship

I have this Recipe entity with ManyToMany relationship with Category entity
#ManyToMany
#JoinTable(name = "recipe_category", joinColumns = #JoinColumn(name =
"recipe_id"),
inverseJoinColumns = #JoinColumn(name = "category_id"))
private Set<Category> categories;
The relationship in the Category entity is this.
#ManyToMany(mappedBy = "categories")
private Set<Recipe> recipes;
The Recipe, Category, Recipe_Category gets created along with a bunch of other tables based on other entities. However, when I edit Recipe, the data in the join table Recipe_Category gets deleted.
Why is this behavior and what I need to do to fix it?
Thanks in advance.

Resources