Spring Boot #Formula displaying same likeCount on every result - spring

I'm having a problem with my #Formula field. I have three tables: user_acc, song and user_likes_song. I'm trying to display likeCount on songs based on how many times the songs ID appears in the many-to-many table.
My #Formula field in the Song entity looks like this:
#Formula("(SELECT COUNT(s.id) FROM user_acc u INNER JOIN user_likes_song us on u.id = us.user_id " +
"INNER JOIN song s on us.song_id = s.id WHERE us.song_id = s.id )")
private Long likeCount;
Currently when I like a song for the first time it shows "likeCount: 1" on every result. After I like another song it returns "likeCount: 2" on every result and so on.
Seems to me like it's counting all the likes in total, not for the specific song. How can I make it so it so it shows how many times a specific song ID appears in the many-to-many table?

You do the match with every song rows :
INNER JOIN song s on us.song_id = s.id WHERE us.song_id = s.id
What you want is restricting it to the current song entity instance.
In fact, if the #Formula annotation is specified on a field of the Song entity, you don't want to specify Song in the query, instead you want to directly refer the field of the current entity (here id), that is :
WHERE us.song_id = id
So this should do the job :
#Formula("(SELECT COUNT(*) FROM user_acc u INNER JOIN user_likes_song us on u.id = us.user_id " + "WHERE us.song_id = id )")
And I think that you could also simplify more in this way :
#Formula(" (SELECT COUNT(*) FROM user_likes_song us WHERE us.song_id = id) ")
because the join with user account doesn't matter.

Related

Query ManyToMany SpringBoot

I have the following modeling:
table hackathon
idEvent int pk ai
...
table team
idTeam int pk ai
...
table hackathon_has_team
hackathon_id int
team_id int
....
And I need to select all the teams that are in an event by event id and I'm breaking my head with it, can anyone help?
I'm trying to do this but it does not work:
#Query("SELECT t "
+ "FROM Team t INNER JOIN hackathon_has_team "
+ "ON hackathon_has_team.team_id = t.id "
+ "WHERE hackathon_has_team.hackathon_id = :hackathon_id")
public Page<Team> getListAllTeamsByIdOfHackathon(#Param("hackathon_id ") Long id, Pageable pageable);
You might need to provide more to get more, but depending on how you are obtaining the list of the teams, you could try:
select * from event_has_team
where (select team_id from table team)
This selects everything from the event_has_team table where the team_id is in the team table. you can also add a where clause for teams you've identified in that sub-select or nit he main select, depending on what you really need.

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

Query to return distinct records ordered by newest association

I have a simple relation
Playlist (id, title)
which has_many
Playlistships(playlist_id, post_id)
A Playlistship is an association between the Playlist and Post classes. When a user adds a 'post' to a 'playlist', a new 'playlistship' is created. When a 'post' is removed from a 'playlist', the corresponding 'playlistship' is destroyed.
I would like to create a query which would return 'Playlists' in order of playlistships.created_at
Basically, I want to have a view which shows playlists which have recently had posts added to them via the Playlistship class.
Try something like:
select * from Playlists P
join Playlistships S on P.id = S.playlist_id
order by S.created_at
To get the most recent Playlistship for each Playlist (that has any posts):
select * from Playlists P
join Playlistships S on P.id = S.playlist_id
where S.created_at = (select max(created_at) from Playlistships where playlist_id = P.id)
order by P.id

Linq left outer group by, then left outer the group

I've this query that i'm trying to put as linq:
select *
from stuff
inner join stuffowner so on so.stuffID = stuff.stuffID
left outer join (select min(loanId) as loanId, stuffownerId from loan
where userid = 1 and status <> 2 group by stuffownerId) t on t.stuffownerid = so.stuffownerid
left outer join loan on t.LoanId = loan.LoanId
when this is done, I would like to do a linq Group by to have Stuff has key, then stuffowners + Loan as value.
I can't seem to get to a nice query without sub query (hence the double left outer).
So basically what my query does, is for each stuff I've in my database, bring the owners, and then i want to bring the first loan a user has made on that stuff.
I've tried various linq:
from stuff in Stuffs
join so in StuffOwners on stuff.StuffId equals so.StuffId
join tLoan in Loans on so.StuffOwnerId equals tLoan.StuffOwnerId into tmpJoin
from tTmpJoin in tmpJoin.DefaultIfEmpty()
group tTmpJoin by new {stuff} into grouped
select new {grouped, fluk = (int?)grouped.Max(w=> w.Status )}
This is not good because if I don't get stuff owner and on top of that it seems to generate a lot of queries (LinqPad)
from stuff in Stuffs
join so in StuffOwners on stuff.StuffId equals so.StuffId
join tmpLoan in
(from tLoan in Loans group tLoan by tLoan.StuffOwnerId into g
select new {StuffOwnerId = g.Key, loanid = (from t2 in g select t2.LoanId).Max()})
on so.StuffOwnerId equals tmpLoan.StuffOwnerId
into tmptmp from tMaxLoan in tmptmp.DefaultIfEmpty()
select new {stuff, so, tmptmp}
Seems to generate a lot of subqueries as well.
I've tried the let keyworkd with:
from tstuffOwner in StuffOwners
let tloan = Loans.Where(p2 => tstuffOwner.StuffOwnerId == p2.StuffOwnerId).FirstOrDefault()
select new { qsdq = tstuffOwner, qsdsq= (int?) tloan.Status, kwk= (int?) tloan.UserId, kiwk= tloan.ReturnDate }
but the more info i get from tLoan, the longer the query gets with more subqueries
What would be the best way to achieve this?
Thanks

Linq, Left Join and Dates

So my situation is that I have a linq-to-sql model that does not allow dates to be null in one of my tables. This is intended, because the database does not allow nulls in that field. My problem, is that when I try to write a Linq query with this model, I cannot do a left join with that table anymore because the date is not a 'nullable' field and so I can't compare it to "Nothing".
Example:
There is a Movie table, {ID,MovieTitle}, and a Showings table, {ID,MovieID,ShowingTime,Location}
Now I am trying to write a statement that will return all those movies that have no showings. In T.SQL this would look like:
Select m.*
From Movies m Left Join Showings s On m.ID = s.MovieID
Where s.ShowingTime is Null
Now in this situation I could test for Null on the 'Location' field but this is not what I have in reality (just a simplified example). All I have are non-null dates.
I am trying to write in Linq:
From m In dbContext.Movies _
Group Join s In Showings on m.ID Equals s.MovieID into MovieShowings = Group _
From ms In MovieShowings.DefaultIfEmpty _
Where ms.ShowingTime is Nothing _
Select ms
However I am getting an error saying
'Is' operator does not accept operands of type 'Date'. Operands must be reference or nullable types.
Is there any way around this? The model is correct, there should never be a null in the Showings:ShowTime table. But if you do a left join, and there are no show times for a particular movie, then ShowTime SHOULD be Nothing for that movie...
Thanks everyone for your help.
Using a left join isn't really helping you here. Since there can never be any results in the right-hand table, you might as well just retrieve the left-hand table and only the left. This is a simple "not in" / "not exists" query:
From m in dbContext.Movies _
Where Not dbContext.Showings.Any(Function(s) s.MovieID = m.MovieID) _
Select m
If there is no record in the Showings table, then the entire object in the query should be nothing. The date should never come into play under such a scenario. A left join would be written like this, selecting only the movies where the showing is missing
Dim query = From m In dbContext.Movies _
Group Join s In dbContext.Showing On m.ID Equals s.MovieID Into g = Group _
From item In g.DefaultIfEmpty() _
Where item Is Nothing _
Select m

Resources