JpaRepository find by manyToMany attribute - spring

Let's imagine classic example of manyToMany relation. I have entities Student and Course and manyToMany relation table between those two entities.
#Entity
data class Student(
#Id
val id: UUID,
val name: String,
#ManyToMany
val courses: Set<Course>
)
#Entity
data class Course(
#Id
val id: UUID,
val title: String,
#ManyToMany
val students: Set<Student>
)
repository can looks like this:
#Repository
interface StudentRepository : JpaRepository<Student, UUID> {
fun findAllByCoursesTitle(title: String): List<Student>
}
Function findAllByCoursesTitle should return all student signed up for math, for example.
My problem is:
How will function looks like when i need to return all students signed up for two specific courses. But i need it for dynamic number of courses, 1 or more.
for example input to function would looks like listOf("math", "geography") or in case of course_ids listOf("UUID", "UUID"). It does not matter if it will be ID or title. What is doalbe.
When i would want to write sql query for that it would looks like this:
SELECT student.id, sc1.course_id, sc2.course_id FROM student
JOIN student_course cs1
ON student.id = cs1.student_id
JOIN student_course cs2
ON student.id = cs2.student_id
WHERE cs1.course_id = ?
AND cs2.course_id = ?
But as i said, i need to have it done for various number of courses.
Please somebody advise.

If you want to resolve logic at SQL statement you can try something like this:
SELECT st.id, sc.course_id, sc.course_id FROM student as st
JOIN (
SELECT st.id as stId, sum(case when c.id IN (:courseIdList) then 1 else 0 end) as cc FROM student as std
JOIN student_course as cs ON std.id = cs.student_id
JOIN cource as c ON c.id = cs.cource_id
GROUP BY (st.id) having cc >= :minimumCourseNumbers
) A on A.stId = st.id
There're courseIdList: List course Ids. minimumCourseNumbers: Minimum course numbers that student must register.
However, I think the logic should move to application to filter.

Related

Add extra condition to jointable in springboot

I have 2 tables which are related using a mapping table i.e FK of these tables are stored in a mapping table (Joining table).
Users {
uid,
uname
}
Dept {
deptid,
dept_name
}
User_Dept{
ud_id,
uid
deptid
status
}
So in my User Entity i have ManytoOne relation with Dept Entity and have added #Jointable annotation to joining table ( User_Dept) like below
User.java
````#ManyToOne
````#JoinTable(
````name="UserDept",
````joinColumns = ````{#JoinColumn(name="uid",referencedColumnName="uid")},
```` inverseJoinColumns = {#JoinColumn(name="deptid", ````referencedColumnName="deptid")}
````)
````private Dept dept;
}
All good!!
But i have a business scenario to fetch only those users belonging to a particular Dept and who are 'active'.
Basically i need to add extra condition to my #jointable(user_dept) to fetch those users whose "status=active" from user_dept table.
I have tried adding #WhereJoinTable(clause = "status=active") like below
class User {
````#JoinTable(
```` name="UserDept",
````joinColumns = ````{#JoinColumn(name="uid",referencedColumnName="uid")},
```` inverseJoinColumns = {#JoinColumn(name="deptid", ````referencedColumnName="deptid")}
````)
````#WhereJoinTable(clause = "status=active")
````}
And also #where(clause = "status=active") at class level.Nothing works.
Issue:
1. where annotation adds a condition to the base query on User table instead of user_dept table.
2. wherejointable annotation- doesnt seem to have any impact.
3. Tried adding #where on userdept class (based on point 1) , but no luck.
Can someone help?
Also if you can propose any alternate solution even thatworks

Convert inner join native query to jpql

I have this method
#Query("select * from feed_tbl feed inner join view_tbl viewers on feed.id <> viewers.feed_id where viewers.user_id = :userId", nativeQuery = true)
fun findAll(#Param("userId") userId: Long): List<Feed>
entities:
User,
Feed
view_tbl is JoinTable in user entity
You should be able to use not in construct:
select f from Feed f where f not in (
select u.feeds from User u where u.id = :userId
)
Of cause you will need to map User to Feed as many-to-many

Springboot jpa, get rows with specific fields using two joins

I have entities :Student, Class, Room.
student M-M class, student M-M rooms, thus two junction tables. Now I want to get all students assigned to class X and room Y. Thus I've made:
#Query("SELECT s from Student s INNER JOIN s.classes c INNER JOIN s.rooms r WHERE c.id LIKE ?1 AND r.id LIKE ?2")
Page<Student> findAllInClassAndRoom(final Long classId, final Long roomId, final Pageable pageable);
But it gives me wrong results. Is there an error in my query ?
The only error in your query is the LIKE statement. Just change the equal sign "=". As below:
#Query("SELECT s from Student s INNER JOIN s.classes c INNER JOIN s.rooms r WHERE c.id = ?1 AND r.id = ?2")
Page<Student> findAllInClassAndRoom(final Long classId, final Long roomId, final Pageable pageable);
The LIKE statement allows a greater mass of data. Because it would allow any Room or Class that part of the code is the id entered as a parameter.
LIKE statement specification

How can I linq 3 tables

How can I linq 3 tables where I can link a student to a school. Tables are: Students, Depart, School.
studentId(pk), departId(fk) departId(pk), schoolId(fk) schoolId(pk)
Below is linking two tables
#foreach (var student in Model.students.Where(s => s.schoolId == item.schoolId))
what you want exactly ? you can join them ...
var query = (from depart in Model.Depart
join school in Model.School on depart.departId equals school.departId
join student in Model.students on school.schoolId equals student.schoolId
where students.schoolId == item.schoolId
select new
{
depart,
school,
student
});
or...
If you have your associations cdonfigured properly, instead of joins, you could also use the associations:
var query = from school in Model.Schools
from dept in school.Departments
from student in dept.Students
select new { student, dept, school};

System.Linq.Dynamic to select a collection inside of a collection from Entity Framework IQueryable

I have an EF model with the relationship User->Roles. It's a one to many relationship in our database. I would like to select the ID from role's record and the name from the user's records.
What I have come up with works for one-to-one relationships. I'm not sure how to generate the a list inside of dynamic linq. Maybe a SelectMany?
User table: Users
Join Table: User_Role
Role Table: Roles
//does not select inside a collection of USER_ROLES
q= query.Select(" new ( ID, (new (USER_ROLES.ID as ID) as USER)")
//not valid
//q = query.Select(" new ( ID, (new List<Object> (USER_ROLES.ID as ID) as USER)") something I figure this would give me a list of User_Role's ID
//not valid
//q = query.Select(" new ( ID, (new List<Object> (USER_ROLES.ROLE.ID as ID) as USER)") something I figure this would give me a list of Role's ID
Update I'm getting closer. I used a selectmany, but the results are duplicated
q = query.SelectMany("USER_ROLES","new (inner as myUSER,outer as myROLE) ").SelectD("new (myROLE.ID as ROLE_ID, new( myROLE.NAME, myUSER.USER.FIRSTNAME,myUSER.USER.ID)as user)")
The results look like this:
Role->User_Role A-> User A
User_Role A-> User B ..notice the repeat of "User_Role A"
User_Role A-> User C
it should be
Role->User Role a -> User A
+ User B
+ User C

Resources