I am trying to implement an example like this: A Person class has a list of places that it likes. But when I want to query it, I want result as each person with only the most favorite place(just the first one not all of them). So I have done this:
#Entity
class Person{
...
#ManyToMany(cascade = {CascadeType.REFRESH,CascadeType.PERSIST}, fetch = FetchType.EAGER)
#JoinTable(name = "person_favorite_place",
joinColumns = #JoinColumn(name = "person_id", referencedColumnName = "id"),
inverseJoinColumns = #JoinColumn(name = "place_id", referencedColumnName = "id")
)
#OrderColumn(name="favorite_place_order")
List<Place> favoritePlaces;
}
And in repository, I did:
public interface PersonRepository extends JpaRepository<Person, Long> {
#Query(value = "select person0_.id as id1_0_0_, person0_.age as age2_0_0_, person0_.name as name3_0_0_, favoriteme1_.person_id as person_id1_1_1_, place2_.id as place_id2_1_1_, favoriteme1_.favorite_place_order as favorite3_1_, place2_.id as id1_3_2_, place2_.invented as invented2_3_2_, place2_.name as name3_3_2_ from person person0_ left outer join person_favorite_place favoriteme1_ on person0_.id=favoriteme1_.person_id left outer join place place2_ on favoriteme1_.place_id=place2_.id where person0_.id=:personId and favoriteme1_.favorite_place_order = 0", nativeQuery = true)
Person getPersonWithFavoritePlace(#Param("personId") Long personId);
}
As expected, the query needs to return 1 Place for each Person but it always returns all the places that Person likes. What am I doing wrong in here?
Related
I am building a spring boot backend and trying to solve my Lazy Loading Problems with a Dto or the join fetch solution. I've got the following entity:
#Entity
public class Project implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
//Some other stuff
#OneToMany(cascade = CascadeType.REMOVE)
#JoinTable(name = "project_categories",
joinColumns = #JoinColumn(name = "project_id", referencedColumnName = "id"),
inverseJoinColumns = #JoinColumn(name = "categories_id", referencedColumnName = "id"))
private Set<Categories> categories;
#OneToMany(cascade = CascadeType.REMOVE)
#JoinTable(name = "project_services",
joinColumns = #JoinColumn(name = "project_id", referencedColumnName = "id"),
inverseJoinColumns = #JoinColumn(name = "services_id", referencedColumnName = "id"))
private Set<Services> services;
//Constructors, Getters, Setter, ...
And in addition to that the Categories/Services Entity.
#Entity
#Table(name = "categories_table")
public class Categories {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private Long catId;
#ManyToOne
#JsonIgnore
private Project project;
//Construcor, Getter, Setter, ...
Now as I mentioned before I've tried to use a dto or the Join fetch method.
With my Join Fetch Method I've got the following Repo setup:
#Query("SELECT p FROM Project p JOIN FETCH p.categories " +
"JOIN FETCH p.services WHERE p.id = :projectId")
Optional<Project> findFullProjectById(#Param("projectId") Long id);
Nothing special here, but when I try to run it I get a ObjectNotFound Exception. But I know for sure it exists.
With the dto approach I've got the following setup:
#Query("SELECT new path.ProjectDto(p, p.categories, " +
"p.services) FROM Project p WHERE p.id = :projectId")
Optional<Project> findFullProjectById(#Param("projectId") Long id);
Here I've got a SQL Syntax Error when executing the above method.
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '. as col_1_0_, . as col_2_0_ from Project project0_ inner join project_categorie' at line 1
Which makes sense, because spring boot tries to execute the following query:
select project0_.id as col_0_0_, . as col_1_0_, . as col_2_0_ from Project project0_ inner join project_categories categories1_ on project0_.id=categories1_.project_id inner join categories_table categories2_ on categories1_.categories_id=categories2_.id inner join project_services services3_ on project0_.id=services3_.project_id inner join services_table services4_ on services3_.services_id=services4_.id where project0_.id=?
I really hope some of you guys could help me here.
Cheers, Nicklas
Scenario:
I have two entities User and Program
#Entity
#Table(name = "user")
public class UserEntity implements Serializable{
#Id
public Long id;
public String firstName;
public String email;
#OneToOne(cascade = CascadeType.ALL)
#JoinTable(
name = "user_program",
joinColumns = {
#JoinColumn(name = "user_id", referencedColumnName = "id")
},
inverseJoinColumns = {
#JoinColumn(name = "program_id", referencedColumnName = "id")
}
)
public ProgramEntity program;
}
JPQL:
SELECT
Program.name,
COUNT(user.id) AS user_count
FROM UserEntity AS user
INNER JOIN ProgramEntity AS program on ________ GROUP BY Program.name
I tried to get the number of users in each program but I couldn't get the result due to the JoinTable (intermediate table) is not an entity. Can anyone suggest a JPQ to connect the join table?
You can join using the entity object, 'ON' is not necessary. For you example,
SELECT prg.name, COUNT(user.id) AS user_count FROM UserEntity AS user INNER JOIN user.program AS prg GROUP BY prg.name
I would like to query all products for a company. The products should be loaded with the list of countries. I managed to write a Spring JPA repository method to query what I want but I wonder why I need a DISTINCT clause.
If I run the following query, I get one product per country. So if a product has 3 countries, the query will return the same 3 rows. Can you explain why?
#EntityGraph(attributePaths = "countries", type = EntityGraph.EntityGraphType.LOAD)
List<Product> findByCompanyIdOrderByIdAsc(Long companyId);
So to fix that issue I added a Distinct clause which return what I want.
#EntityGraph(attributePaths = "countries", type = EntityGraph.EntityGraphType.LOAD)
List<Product> findDistinctByCompanyIdOrderByIdAsc(Long companyId);
I have the same issue if I run a JPQL Select p from Product LEFT JOIN FETCH p.countries WHERE p.company.id = ?1 which is equivalent to findByCompanyIdOrderByIdAsc.
The entities:
public class Product implements Serializable {
#ManyToOne
#JsonIgnore
private Company company;
#ManyToMany
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
#JoinTable(name = "product_country",
joinColumns = #JoinColumn(name="product_id", referencedColumnName="id"),
inverseJoinColumns = #JoinColumn(name="country_id", referencedColumnName="id"))
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id",
resolver = EntityIdResolver.class, scope = Country.class)
#JsonIdentityReference(alwaysAsId = true)
private Set<Country> countries = new HashSet<>();
}
public class Country implements Serializable {
}
I have two entities. For example, posts and tags to it.
I have to write a method that will take only posts, which have all of tags, mentioned in query.
I tried
#Query("select distinct p from posts p join p.tags t where t in ?1")
Page<Post> findDistinctByTagsIn(Set<Tag> tagSet, Pageable pageable);
However it takes Post if at least one of its tags included in tagSet.
How can I solve this using only HQL and JPA Repositories?
UPD:
#ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinTable(name = "posts_tags", joinColumns = {
#JoinColumn(name = "post_id", nullable = false, updatable = false)},
inverseJoinColumns = {#JoinColumn(name = "tag_id")})
public Set<Tag> getTags() {
return tags;
}
Add to you Tag class next ManyToOne relation:
#Entity
public class Tag{
...
private Post post;
#ManyToOne
#JoinTable(name = "posts_tags",
joinColumns = {#JoinColumn(name = "tag_id")},
inverseJoinColumns = {#JoinColumn(name = "post_id")})
public Post getPost(){
return post;
}
...
}
Let's try to build query.
We don't need posts that have tags that are out of our list of tags. We will select them with next query:
select t.post from Tag t where t not in (:tagSet) and t.post is not null
And we don't need posts, that have not any tags at all. Let's select them as well:
select p from Post p where p.tags is empty
Now let's join our queries together:
select p from Post p where
p not in (select t.post from Tag t where t not in (:tagSet) and t.post is not null)
and p not in (select p2 from Post p2 where p2.tags is empty)
And you can use named parameter to bind this query:
Page<Post> findDistinctByTagsIn(#Param("tagSet") Set<Tag> tagSet, Pageable pageable);
I have following entity:
public final class Stock implements Serializable {
#JsonIgnore
#ManyToMany(mappedBy = "stocks", fetch = FetchType.LAZY)
private Set<User> users = new HashSet<>();
[Other fileds]
[getters/setters]
}
And i would like write query in jpql to get top5 Stock entity based on size of set users. So far i write native query in sql and it looks like:
SELECT s.ticker, COUNT(s.ticker)
FROM t_stock s INNER JOIN t_user_stocks us ON s.id = us.stock_id
INNER JOIN t_user u on us.user_id = u.id GROUP BY s.ticker ORDER BY count DESC
And i want a jqpl query which return top 5 stocks entity. Could someone help me?
Assuming your entity is mapped as follows.
#Entity
public class Stock {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column
private String ticker;
#JsonIgnore
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(name = "stock_user", joinColumns = { #JoinColumn(name = "STOCK_ID", nullable = false, updatable = false) }, inverseJoinColumns = { #JoinColumn(name = "USER_ID", nullable = false, updatable = false) })
private Set<User> users = new HashSet<User>();
}
I did the following using native SQL to get the result.If you insist on using JPQL, the answer here is your friend.
public interface StockRepository extends JpaRepository<Stock, Integer> {
#Query(value = "SELECT s.ticker, COUNT(s.ticker) FROM stock s INNER JOIN "
+ "stock_user us ON s.id = us.stock_id INNER JOIN user u on us.user_id = u.id GROUP BY s.ticker order by count(*) desc limit 1", nativeQuery = true)
public List<Object[]> findStock();
}