QuerySyntaxException in Spring Data JPA custom query - spring

I have a Entity:
#Entity
#Table(name = "story", schema = "")
#Data
public class Story implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "sID", unique = true, nullable = false)
private Long sID;
#Column(name = "vnName", nullable = false)
private String vnName;
#Temporal(TemporalType.TIMESTAMP)
#DateTimeFormat(pattern = "dd-MM-yyyy HH:mm:ss")
#Column(name = "sUpdate", length = 19)
private Date sUpdate;
}
And:
#Entity
#Table(name = "chapter", schema = "")
#Data
public class Chapter implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "chID", unique = true, nullable = false)
private Long chID;
#Column(name = "chName", nullable = false)
private String chName;
#JoinColumn(name = "sID", referencedColumnName = "sID")
#ManyToOne(fetch = FetchType.LAZY)
private Story story;
}
I had created custom pojo to get the latest update story with the latest chapter:
#Data
public class NewStory{
private Story story;
private Chapter chapter;
}
but when I get list :
#Repository
public interface StoryRepository extends CrudRepository<Story, Long> {
#Query(value="SELECT NEW com.apt.truyenmvc.entity.NewStory(s as newstory, c as newchapter)"
+ " FROM story s LEFT JOIN (SELECT * FROM Chapter c INNER JOIN "
+ " (SELECT MAX(c.chID) AS chapterID FROM Story s LEFT JOIN Chapter c ON s.sID = c.sID GROUP BY s.sID) d"
+ " ON c.chID = d.chapterID) c ON s.sID = c.sID order by s.sUpdate desc")
public List<NewStory> getTopView();
}
Error:
Warning error: org.hibernate.hql.internal.ast.QuerySyntaxException: story is not mapped.
Who could help me fix it? Or could it be done in a different way?

The error is pretty self explainatory. And its just a typo in your query. You are using story. And obviously thats not mapped as an Entity.
Fix it to Story

Related

Trying to Convert a SQL Query to a JPA Query

I want to convert this sql query to a JPA query, but I can't seem make sense of it... Should I use findByMarinaIdAndMovementGroupMeanId?? or findByMarinaIdAndMovementGroupMeanIdAndMovementMeanId??
Sql:
select m.* from movement_group m
join movement_group_mean mgm on m.id = mgm.movement_group_id
join movement_mean mm on mgm.movement_mean_id = mm.id
where mm.id = 1 and m.marina_id = :marinaId and mm.active = true;
MovementGroup:
#Entity
public class MovementGroup {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
private String code;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
private Boolean active;
private String iconUrl;
#OneToMany(mappedBy = "movementGroup")
private Set<MovementGroupMean> movementGroupMeans;
#JsonIgnore
#ManyToOne()
#JoinColumn(name = "marina_id")
private Marina marina;
MovementGroupMean:
#Entity
public class MovementGroupMean {
#EmbeddedId
#JsonIgnore
private MovementGroupMeanPK movementGroupMeanPK;
#JsonBackReference
#ManyToOne
#JoinColumn(name = "movement_group_id", insertable = false, updatable = false)
private MovementGroup movementGroup;
#ManyToOne
#JoinColumn(name = "movement_mean_id", insertable = false, updatable = false)
private MovementMean movementMean;
MovementMean:
#Entity
public class MovementMean {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
#Enumerated(EnumType.STRING)
private MovementMeanType movementMeanType;
private Boolean active;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
#JsonBackReference
#ManyToOne()
#JoinColumn(name = "marina_id")
private Marina marina;
Not sure where the problem lies, so excuse the lengthy explanation on SQL->JPQL:
Replace your table names with your entity names
movement_group -> MovementGroup
Replace your joins with the java references, letting JPA use the relationship mapping you've defined instead.
"join movement_group_mean mgm on m.id = mgm.movement_group_id" becomes "join m.movementGroupMeans mgm"
"join movement_mean mm on mgm.movement_mean_id = mm.id becomes "join mgm.movementMean mm"
Only tricky spot is your entities do not define a basic mapping for the marina_id value. So to get at m.marina_id, you will have to use the 'marina' reference and use its presumably ID value:
"m.marina_id = :marinaId" -> "m.marina.id = :marinaId"
Giving you JPQL:
"Select m from MovementGroup m join m.movementGroupMeans mgm join mgm.movementMean mm where mm.id = 1 and m.marina.id = :marinaId and mm.active = true"

How to write custom findAll() with Specification in JPA repository

When I use skuRepository.getAll(), it works OK, but when I apply filters, defined in Specification (List filteredRegs = skuRepository.getAll(specification)) I still get all the rows of the table
What should i do to apply the specifications to my custom method?
public interface SkuRepository extends CrudRepository<Sku, Integer>, JpaSpecificationExecutor<Sku> {
#Query("select s from Sku s join fetch s.unit un join fetch s.supplier sup WHERE un.id = sku_unit_id AND sup.id = supplier_id")
List<Sku> getAll(#Nullable Specification<Sku> var1);
#Query("select s from Sku s join fetch s.unit un join fetch s.supplier sup WHERE un.id = sku_unit_id AND sup.id = supplier_id")
List<Sku> getAll();
}
UPD:
Here is my entities.
When I make sampling by a Sku table using the Specification API, I see three separate selects in log: one for Sku entity, one for Unit and one for Suppliers. I want my app to make one select with joins.
I read that this is due to the fact that I use EAGER fetch type, so I change it to LAZY, but then I got another problem: "InvalidDefinitionException: No serializer found..." This is logical because related entities Unit and Supplier are not loaded.
Then I decided to write my custom getAll() with request:
#Query("select s from Sku s join fetch s.unit un join fetch s.supplier sup WHERE un.id = sku_unit_id AND sup.id = supplier_id ORDER BY s.name")
But now it does not support Specification.
Please advise what to do.
#Entity
#Table(name = "sku")
public class Sku implements Cloneable, CloneableEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private int id;
#Column(name = "sku_code", length = 6, nullable = false, unique = true)
private String code;
#Column(name = "sku_name", nullable = false)
private String name;
#ManyToOne(cascade = CascadeType.PERSIST, fetch = FetchType.LAZY)
#JoinColumn(name = "sku_unit_id", nullable = false)
private Unit unit;
#ManyToOne(cascade = CascadeType.PERSIST, fetch = FetchType.LAZY)
#JoinColumn(name = "supplier_id", nullable = false)
private Supplier supplier;
#Column(name = "qty_in_sec_pkg")
private int quantityInSecondaryPackaging;
#Column(name = "sku_is_active", nullable = false)
private boolean isActive;
//constructors, getters, setters
}
#Entity
#Table(name = "units")
public class Unit {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id ")
private int id;
#Column(name = "unit", nullable = false, unique = true)
private String unit;
#Column(name = "description")
private String description;
//constructors, getters, setters
}
#Entity
#Table(name = "suppliers")
public class Supplier {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id ")
private int id;
#Column(name = "supplier_code", length = 6, nullable = false, unique = true)
private String supplierCode;
#Column(name = "supplier_name", nullable = false)
private String name;
#Column(name = "create_date", length = 19, nullable = false)
private String createDate;
#Column(name = "update_date", length = 19)
private String updateDate;
//constructors, getters, setters
}
You can't mix #Query and Specification
You can only use JpaSpecificationExecutor interface methods to use Specification.
Find more details here

Join Two Tables without foreign keys in Spring Boot with similar Ids

Here I have two tables; both have IDs as primary keys. I want to know how to join these tables without foreign keys, based on their IDs. What should be the service implementation and what should be in the repository? How to write #Query with JOINS?
#Entity
#Table(name = "procedures")
#JsonIgnoreProperties({ "hibernateLazyInitializer", "handler" })
public class Procedure implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ProcedureId")
private int id;
#Column(name = "ProcedureName")
private String name;
#Column(name = "ProcedureCode")
private String code;
#Column(name = "ProcedureDesc")
private String desc;
// getters and setters
}
#Entity
#Table(name = "cliniciandescriptor")
public class CPTClinicianDescriptor {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "Id")
private int id;
#Column(name = "ConceptId")
private int conceptId;
#Column(name = "CPTCode")
private String cptCode;
#Column(name = "ClinicianDescriptorId")
private int clinicianDescriptorId;
#Column(name = "ClinicianDescriptor")
private String clinicianDescriptor;
// getters and setters
}
You can use the JOIN on syntax like in SQL
For example
select p from Procedure p join CPTClinicianDescriptor c on c.id = p.id;
Read more about that topic here:
https://72.services/how-to-join-two-entities-without-mapped-relationship/
Considering it as One-to-One relation, you can use something like this.
#Entity
#Table(name = "procedures")
#JsonIgnoreProperties({ "hibernateLazyInitializer", "handler" })
public class Procedure implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ProcedureId")
private int id;
#Column(name = "ProcedureName")
private String name;
#Column(name = "ProcedureCode")
private String code;
#OneToOne(optional = false)
#JoinColumn(name = "id", updatable = false, insertable = false)
private CPTClinicianDescriptor descriptor;
#Column(name = "ProcedureDesc")
private String desc;
// getters and setters
}

Hibernate session closed with large volume

I try to retrieve the data from a table linked to a parent table with the following entities:
Entity
#Table(name = "REF_BONJOUR_UNITE")
#NamedQuery(name = "UniteEntity.findAll", query = "SELECT u FROM UniteEntity u")
public class UniteEntity implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "CODE_UNITE")
private String codeUnite;
// bi-directional many-to-one association to Insee
#OneToMany(mappedBy = "refBonjourUnite", fetch = FetchType.LAZY, cascade = CascadeType.MERGE )
private List<Insee> refBonjourInsees;
and the daughter entity :
#Entity
#Table(name = "REF_BONJOUR_INSEE")
#NamedQuery(name = "Insee.findAll", query = "SELECT i FROM Insee i")
public class Insee implements Serializable {
private static final long serialVersionUID = 1L;
#EmbeddedId
private InseePK id;
#Temporal(TemporalType.DATE)
#Column(name = "DATE_FIN_INSEE_GEO")
#IsOracleDate
private Date dateFinInseeGeo;
private String tylemt;
// bi-directional many-to-one association to UniteEntity
#ManyToOne
#JoinColumn(name = "CODE_UNITE_FK", insertable = false, updatable = false)
private UniteEntity refBonjourUnite;
When i try to access this list with a large amount of data, i get a failed to lazily initialize a collection of role, here exactly :
List<Insee> codeInsees = unite.getRefBonjourInsees();
Insee codeInsee = codeInsees.get(0)

Spring Framework + Spring Data + Hibernate Jpa OneToMany child removal fails

I have an unidirectional OneToMany JPA entity mapping in my (Spring Framework + Spring Data + Hibernate JPA) project. Entity classes are like in the following code.(I have removed irrelevant class members for brevity).
#Entity
#Table(name = "employees")
class Employee{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Integer id;
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
#JoinColumn(name = "employee_id")
private List<DepartmentAssignment> departmentAssignments = new ArrayList<>();
}
#Entity
#Table(name = "department_assignments")
class DepartmentAssignment{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Integer id;
#NotNull
#Column(name = "employee_id")
private Integer employeeId;
#NotNull
#Column(name = "department_id")
private Integer departmentId;
}
#Entity
#Table(name = "departments")
class Department{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Integer id;
}
And, in one of my service classes have a method to remove a DepartmentAssignment from an Employee like below.
public Employee deleteDepartmentAssignment(Integer empId, Integer deptAssignmentId) {
Employee employee = employeeRepository.findOne(empId);
if(employee != null) {
for ( DepartmentAssignment da : employee.getDepartmentAssignments()) {
if(da.getId().equals(deptAssignmentId)) {
employee.getDepartmentAssignments().remove(da);
employee = employeeRepository.save(employee);
break;
}
}
}
return employee;
}
However, calling above methods gives me an error: org.hibernate.exception.ConstraintViolationException ,and in the SQL log, I can see Column 'employee_id' cannot be null error for the last SQL statement of the transaction.
Can anybody tell me what I'm doing wrong here and how to get it fixed?
You don't need to add
#NotNull
#Column(name = "employee_id")
private Integer employeeId;
to the Employee, if you use #JoinColumn(name = "employee_id"). Try to remove it.
You can try the following, not sure why you use the plain id in the object. Thats not object relational mapping.
For more details see Hibernate triggering constraint violations using orphanRemoval
#Entity
#Table(name = "employees")
class Employee{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "employee", orphanRemoval = true)
private List<DepartmentAssignment> departmentAssignments = new ArrayList<>();
}
#Entity
#Table(name = "department_assignments")
class DepartmentAssignment{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#ManyToOne(optional=false)
private Employee employee;
#ManyToOne(optional=false)
private Department department;
}
#Entity
#Table(name = "departments")
class Department{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
}
You must look .hbm.xml file and you should mapping your Entity in this file and
you can look this example
http://www.mkyong.com/hibernate/hibernate-one-to-many-relationship-example/
I hope it will be useful for you.
try removing
cascade = CascadeType.ALL
but im not 100% sure..

Resources