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

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?

Related

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.

AuditorAware is not working for Many-Many relationship

I use Spring data AuditorAware feature to audit CreatedBy,LastModifiedBy,CreatedDate and LastModifiedDate. It perfectly works for all the entities even when an entity is in one-many relationship. But It doesn't work for many-many relation ship.
For Ex,
I have entities user and user_group with many-many relationship. So it has another table user_group_association with user_id and user_group_id
Whenever there is an create or update in usergroup then audit columns get updated in usergroup table. But within the same transaction if any create/update to user_group_association there is no changes for these columns.
As I define many-many relation ship as below, I wouldn't have an entity class for user_group_association
// bi-directional many-to-many association to Users through
// user_group_association
#ManyToMany(fetch = FetchType.LAZY, cascade = { CascadeType.PERSIST, CascadeType.MERGE })
#JoinTable(name = "user_group_association", joinColumns = #JoinColumn(name = "user_group_id"), inverseJoinColumns = #JoinColumn(name = "user_id"))
private Set<User> users;
How can I force Spring Data to make entires in user_group_association table as well ?

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.

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.

Insert data in intermediate table created by 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.

Resources