Insert data in intermediate table created by spring - spring

I am using spring with JPA and I have 2 model classes
User
Resources
I have defined many to many relation using -
#ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinTable(name = "users_resources", joinColumns = #JoinColumn(name = "user_id", referencedColumnName = "id"), inverseJoinColumns = #JoinColumn(name = "resource_id", referencedColumnName = "id"))
This definition has created another table users_resources.
To insert data in users_resources table, the REST api is sending just the User id [primary key] and Resource Id [primary key].
Is there anyway I can insert data into users_resources without fetching full user object and resource object? I wanted to use native query but it seems PersistenceJPAConfig has noway to run native INSERT query.

If you know Id of the object, and you need object reference (without object details) you could use EntityManager.getReference()
User userReference=em.getReference(User.class,userId);
Resource resourceReference=em.getReference(Resource.class,resourceId);
Using references will not exectue any SELECTs from the database.

Related

Hibernate: lazy loading vs dtos

Imagine having an JPA entity with different lazy loaded fields
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(name = "organisation_teams",
joinColumns = #JoinColumn(name = "id", referencedColumnName = "id", table = "usr_organisation"),
inverseJoinColumns = #JoinColumn(name = "team_id", referencedColumnName = "id", table = "usr_teams")
)
private Set<Team> teams = new LinkedHashSet<>();
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(name = "organisation_associations",
joinColumns = #JoinColumn(name = "parent_id", referencedColumnName = "id", table = "usr_organisation"),
inverseJoinColumns = #JoinColumn(name = "child_id", referencedColumnName = "id", table = "organisation")
)
private Set<Organisation> children = new LinkedHashSet<>();
This entity is now requested by a second service, so we need to convert into a DTO and return via REST for example. Now there can be different scenarios, where for example only the team field is required, only the children field or both.
One could map them always into the DTO, in this case using lazy loading is pointless in my opinion. Are there different elegant options aside of creating different DTOs (containing only the team or only the children fields) and different REST endpoints? I don`t think this would be an elegant solution as well, because you would end up with a bunch of endpoints and dtos.
Additionally Team and Organisation again have lazy loaded fields and the same issue applies again.
I think that what you are looking for might be https://graphql.org/. But for plain REST endpoints I would say different DTOs is the way to go, use inheritance to avoid code duplication.
If you want to improve performance and not lazy load related entities you can specify different named entity graphs and depending on the DTO select the one that eagre loads the required data. See the documentation here: https://docs.oracle.com/javaee/7/tutorial/persistence-entitygraphs001.htm.
Any lazy loaded field that is not mapped to a DTO won't be loaded. So basically you use the same entity with different graphs and different DTOs.

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.

Retrieve data over a many-to-many relationship in a Spring/Hibernate project

I am new to development using Spring framework and Hibernate. And I need to know what is the best practice to retrieve data from multiple tables. Here is a simple scenario:
Assuming a many-to-many relationship with these tables: Students(sid, name), Courses(cid, title), Students-Courses(sid,cid)
I don't have a Model/Entity class for Students-Courses. Here is how I handled the relationship in the "Student" Model/Entity class:
#JsonIgnore
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(
name = "students-courses",
joinColumns = {#JoinColumn(name = "sid", referencedColumnName = "sid")},
inverseJoinColumns = {#JoinColumn(name = "cid", referencedColumnName = "cid")})
So, this class creates both "Students" and "Students-Courses" tables in the database via Hibernate. I also have a separate Model/Entity class for Course.
How can I get the list of all the students including their courses (titles)? I mean multiple records for the students with more than one course
I can create an attribute in the "Student" class like this:
private Set<Course> courses = new HashSet<>();
But it won't be returned back if I use a JpaRepository interface/class like
return studentRepository.findAll();
since it's not a #Column.
Should I write native-SQL code in my class?
Should I create an Immutable Entity class so Hibernate create sort of a database-view object in the data layer?
What is the best practice and how should I do that?

Is it possible to access db tables directly in spring to verify state

I'm quite new to Spring and want to make sure that I am using #JoinTable and #ManuToMany etc correctly.
So I was thinking to test to create and delete some entites from the database and verify that tables such as jointable contains correct data.
My problem is that I don't know how to access this table to verify it's content.
Example:
(Pseudo code)
class Access
Long id
#OneToMany
#JoinTable(
name = "account_role",
joinColumns = #JoinColumn(name = "account_id", referencedColumnName = "id"),
inverseJoinColumns = #JoinColumn(name = "role_id", referencedColumnName = "id"))
Set<Role> roles
class Role
Long id
This should create table named "account_role" that maps the Roles which the Account has. When one account is removed, this table should also be altered. Is it possible to access this table directly (in a convenient way) to verify the content?
I'm using in memory H2 for my tests.
It is possible to do this with JdbcTemplate.

Resources