Hibernate #Query throw syntax error at or near "." - spring-data-jpa

I try to get field tags from the entity Article:
#Getter
#Setter
#Entity
#ToString
#NoArgsConstructor
#AllArgsConstructor
#Table(name = "articles")
public class Article {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Embedded
private Author author;
#Column(unique = true)
private String title;
private String content;
#ElementCollection(targetClass = String.class,
fetch = FetchType.EAGER
)
#CollectionTable(name = "tags",
joinColumns = #JoinColumn(name = "article_id")
)
#Column(name = "tag")
private List<String> tags = new ArrayList<>();
}
With ArticleRepository extends JpaRepository<Article, Long>, JpaSpecificationExecutor<Article> and #Query:
#Query("SELECT " +
" new java.util.ArrayList(a.tags) " +
" FROM Article a " +
" WHERE a.title = :title")
List<String> findAllTagsOfArticle(String title);
And get a result:
Hibernate:
select
. as col_0_0_
from
articles article0_
inner join
tags tags1_
on article0_.id=tags1_.article_id
where
article0_.title=?
2022-07-21 15:17:24.666 WARN 2196 --- [ scheduling-1] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 0, SQLState: 42601
2022-07-21 15:17:24.666 ERROR 2196 --- [ scheduling-1] o.h.engine.jdbc.spi.SqlExceptionHelper : ERROR: syntax error at or near "."
Generated SQL query looks correct but after SELECT hibernate generate .
Why does it happens and how to fix it?

You cannot pass a collection (a.tags) like that. The idea is that the constructor will receive a single row from the query result.
But also, there's no need to use new ArrayList.
This should work:
#Query("select t from Article a join a.tags t where a.title = :title")
List<String> findAllTagsOfArticle(String title);
You can also simplify a bit the mapping:
#ElementCollection
#CollectionTable(name = "tags",
joinColumns = #JoinColumn(name = "article_id")
)
#Column(name = "tag")
private List<String> tags = new ArrayList<>();
There is no need to specify EAGER and the target class in this case.

Related

JPA Repository Query on additional table #ManytoMany

I want to do select like this in my jpa spring repository
SELECT sicknes_id, count(symptomp_id) as ilosc FROM symptomp_sicknes where symptomp_id IN (1,2) group by sicknes_id Order by ilosc DESC;
My enitity
#Entity
#Table(name = "symptomp")
public class Symptomp {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "symptomp_id")
private Long symptomp_id;
#Column(name = "name")
private String name;
#Column(name = "description")
private String description;
#ManyToMany(cascade = {CascadeType.DETACH,CascadeType.MERGE,CascadeType.PERSIST,CascadeType.REFRESH}, fetch = FetchType.LAZY)
#JoinTable(name = "symptomp_sicknes",joinColumns = #JoinColumn(name = "symptomp_id"),inverseJoinColumns = #JoinColumn(name = "sicknes_id"))
private Set<Sicknes> sicknes = new HashSet<>();
#Entity
#Table(name = "sicknes")
public class Sicknes {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "sicknes_id")
private Long sicknes_id;
#Column(name = "name")
private String name;
#Column(name = "description")
private String description;
#ManyToOne(cascade = {CascadeType.DETACH,CascadeType.MERGE,CascadeType.PERSIST,CascadeType.REFRESH}, fetch = FetchType.LAZY)
#JoinColumn(name = "speciesId")
private Species species;
My Symptomp repository:
public interface SymptompRepository extends JpaRepository<Symptomp, Long> {
#Query("select p from Symptomp p where name like ?1%")
public List<Symptomp> findAllBySymptompName(String symptomp);
public Symptomp findByName(String symptomp);
public List<Symptomp> findByNameIn(List<String> list);
Integer countDistinctSymptompByName(String id);
}
How I can create this select in my JPA repository?
I try get value like in select but i got error mapping bean.
You can get query result as List<Object[]> using nativeQuery=true parameter
#Query("SELECT sicknes_id, count(symptomp_id) as ilosc FROM symptomp_sicknes where symptomp_id IN (1,2) group by sicknes_id Order by ilosc DESC", nativeQuery=true)
List<Object[]> getQueryResult();
Other option is to create dto class with appropriate constructor
public class QueryResultDto {
Long sicknesId;
Long count;
public QueryResultDto(Long sicknesId, Long count) {
this.sicknesId = sicknesId;
this.count = count;
}
}
Then using JPQL
#Query("select new yourproject.dtopath.QueryResultDto(...")
List<QueryResultDto> getQueryResult(#Param("symptompIds") List<Long> symptompIds);
If you want to avoid a native Query the best way is to create an Entity for that JoinTable. Then you can query it easily. Additional benefit if this is that if in future a requirement will pop up that you have to store additional attributes in that relation you will have the Entity already there to do that easily.

JPA expecting ID column on joined table

I'm attempting to represent a join table with JPA, however the generated SQL is expecting an id field on one of the tables.
The generated SQL is very close, but appears an ID column is expected on Permission table and used as the FK on the join table, which I was hoping not to do. See schema below:
You can see I am not using an ID column on permission table, instead letting the text representation of the permission be the key.
User.java
#Entity
#Data
#Table(name = "user")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private int accountId;
private String name;
private String email;
private String password;
private boolean admin;
#ManyToMany
#JoinTable(
name = "user_permission",
joinColumns = #JoinColumn(name = "id"),
inverseJoinColumns = #JoinColumn(name = "permission"))
private List<Permission> permissions;
}
Permission.java
#Data
#Entity
public class Permission {
#Id
private String permission;
private String permissionName;
private String permissionDescription;
}
Generated SQL
select
permission0_.id as id1_2_0_,
permission0_.permission as permissi2_2_0_,
permission1_.permission as permissi1_0_1_,
permission1_.permission_description as permissi2_0_1_,
permission1_.permission_name as permissi3_0_1_
from user_permission permission0_
inner join permission permission1_ on permission0_.permission=permission1_.permission
where permission0_.id=?
Error
ERROR 15056 --- [tp1962586186-25] o.h.engine.jdbc.spi.SqlExceptionHelper : Unknown column 'permission0_.id' in 'field list'
The problem was join columns name. It should have been mapped to the mapping tables FK instead of the parent tables PK. Above example is fixed with this change
#ManyToMany
#JoinTable(
name = "user_permission",
joinColumns = #JoinColumn(name = "user_id"),
inverseJoinColumns = #JoinColumn(name = "permission"))
private List<Permission> permissions;

#NamedQuery trying to fetch entity and related entity (#OneToOne relation) by related entity property

There are two entities:
#Entity(name = "Account")
#Table(name = "accounts")
#NamedQuery(name = "findAccountByExtId",
query = "SELECT a " +
"FROM Account a " +
"WHERE a.accountDetails.extId = :extId " +
"AND a.deletedAt IS NULL")
public class Account extends DeletableAudit {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue
private UUID id;
#OneToOne(mappedBy = "parent", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private AccountDetails accountDetails;
and
#Entity(name = "AccountDetails")
#Table(name = "account_details")
public class AccountDetails extends DeletableAudit {
private static final long serialVersionUID = -1L;
#Id
#GeneratedValue
private Integer accDetId;
#OneToOne
#JoinColumn(name = "fk_account")
private Account parent;
#Column
private String extId;
Goal is to return Account and AccountDetials via the external ID. The program won't run due to error:
Failed to create query for method public abstract p.j.o.d.d.Account p.j.o.d.r.AccountRepository.findAccountByExtId(java.lang.String)! No property extId found for type Account!
Already tried different variations of #OneToOne mapping and query, however nothing seems to work.
Second question is whether it is possible to have AccountDetails reference the same ID as Account. I'd like to get rid of accDetId and just store these entities with the same UUID of their parent.

query entity with condition on ManyToMany relation

I have two Entites
#Entity
public Report()
#Id
#Column(name = "REPORT_ID")
private long id;
#JsonIgnore
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(
name="reports_projects",
joinColumns={#JoinColumn(name="report_id", referencedColumnName="REPORT_ID")},
inverseJoinColumns={#JoinColumn(name="project", referencedColumnName="PROJECT_ID")})
private List<Project> projects;
second is:
#Entity(name = "projects")
public class Project
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "PROJECT_ID")
// seems like spring's jpa has issue hanlde "_" between the words
private long id;
#Column(name = "CODE", nullable = false)
private String code;
#Column(name = "DESCRIPTION", nullable = false)
private String description;
#Column(name = "CREATION_DATE", nullable = false)
private Date creationDate;
i'm tring to query reports by projects.code
tried few stuff like
#Query("select reports from org.jpp.domain.quicksearch.ReportQS reports inner join reports.projects p where p.code in :code")
And
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<QuickSearchResult> query = cb.createQuery(QuickSearchResult.class);
Metamodel m = em.getMetamodel();
EntityType<ReportQS> ReportQSMetaModel = m.entity(ReportQS.class);
Root<ReportQS> reportsQS = query.from(ReportQS.class);
Root<Project> projects = query.from(Project.class);
Join<ReportQS, Project> joinReportsProjects = reportsQS.join("projects");
Predicate condition = cb.equal(projects.get("code"),"gnrl");
query.select(reportsQS).where(condition);
TypedQuery<QuickSearchResult> q = em.createQuery(query);
I get empty result for both of the queries
Any idea how to get this to work ?
Thanks in advance,
Oak
Try following code:
String query = "select r from ReportQS r join r.projects p where p.code = :code";
List<ReportQS> reports = em.createQuery(query,ReportQS.class).setParameter("code","grnl").getResultList();
Make sure that ReportQS is name of entity class (in your sample code you have different class name and different entity name used in query).

JPQL NamedQuery: Access attribute of an #Embeddable class from an #ElementCollection reference

The follwing named query
<named-query name="fix.getByProblem">
<query>
SELECT f
FROM Fix f JOIN f.solved s
WHERE s.id IN :ids
</query>
</named-query>
is supposed to return all fixes that solve at least one of the given problems, but fails with the error message
Exception Description: Error compiling the query [fix.getByProblem]:
SELECT f FROM Fix f JOIN f.solved s WHERE s.id IN :ids
], unknown state or association field [id] of class [ProblemHandle].
The model is as follows: (simplified)
Fix.java
#ElementCollection
#CollectionTable(name = "FIX_SOLVED", schema = SCHEMA_NAME, joinColumns = {#JoinColumn(name = "SOURCE_VERSION", referencedColumnName = "version")})
#AttributeOverrides({ #AttributeOverride(column = #Column(name = "SOLVED_ID", nullable = true), name = "id") })
private Collection<ProblemHandle> solved;
ProblemHandle.java
#Embeddable
#Access(AccessType.PROPERTY)
public class ProblemHandle {
private Long id;
...
}
Problem.java
#Entity(name = Problem.ENTITY_NAME)
#Access(value = AccessType.FIELD)
#Table(name = Problem.TABLE_NAME, schema = Problem.SCHEMA_NAME)
#IdClass(ProblemHandle.class)
public class Problem {
public static final String ENTITY_NAME = "problem";
public static final String SCHEMA_NAME = "X";
public static final String TABLE_NAME = "PROBLEM";
#Id
#Column(name="id", nullable = false)
private Long id;
...
}
How can I achieve that without having to change the pattern, e.g. using handles?
You have #Access(AccessType.PROPERTY), so the name of your attribute comes from your get method, not the variable. What is the name of your get method?
Try removing #Access(AccessType.PROPERTY)
Also, what version are you using? Try using the 2.4 release.