speedment / jpa-streamer

JPAstreamer is a lightweight library for expressing JPA queries as Java Streams
GNU Lesser General Public License v2.1
345 stars 35 forks source link

Filter is not applied in the "where" clause #380

Closed fernando88to closed 1 year ago

fernando88to commented 1 year ago

Describe the bug

When doing a left join and making clauses in the left join table, the restriction is not applied in the sql

Expected behavior

That all clauses and were applied in SQL, especially in the table where the inner join is being done

Actual behavior

How To Reproduce

` @Entity @Table(name = "film") public class Film {

@Id
@Column(name = "film_id")
public Integer filmId;

@Column(name = "film_name")
public String name;

@ManyToOne
@JoinColumn(name="language_id", nullable = false)
public Language language;

}

@Entity @Table(name = "language") public class Language {

@Id
@Column(name = "language_id")
public Integer languageId;

@Column(name = "country")
public String country;

}

jpaStreamer.stream(of(Film.class).joining(Film$.language))
.filter(Film$.name.containsIgnoreCase("test")) .filter(film -> film.language.country.equals("BR")) .forEach(System.out::println);

`

Generated SQL

select f1_0.film_id, f1_0.language_id, l1_0.language_id, l1_0.country, f1_0.film_name from film f1_0 left join language l1_0 on l1_0.language_id=f1_0.language_id where lower(f1_0.film_name) like ? escape

Build tool e.g. Gradle 8.1.1

JPAStreamer version e.g. JPAStreamer 3.0.4

JPA Provider e.g. Hibernate 6.2.9.Final

Java Version openjdk 11.0.17 2022-10-18

Additional context

Example repository https://github.com/fernando88to/issuejpastream

julgus commented 1 year ago

Hi Fernando, thank you for the detailed description of your problem. I would not really describe this as a bug - I'll try to explain why.

Your stream has one filter that leverages the JPAStreamer metamodel, and one that uses an anonymous lambda. These will be handled differently:

jpaStreamer.stream(of(Film.class).joining(Film$.language))
     .filter(Film$.name.containsIgnoreCase("test"))       // this is included in the query 
     .filter(film -> film.language.country.equals("BR"))   // this cannot be translated to SQL
     .forEach(System.out::println);

I am assuming you may also wonder how you can filter on the language property. Unfortunately current the answer is that you cannot filter on the joined entities in the database.

fernando88to commented 1 year ago

Thank you for your answer, it helps me understand better