HQL query doesn't order by other mapped entity criteria - java

I have the following entities in a Hibernate - Spring proyect.
Member:
#Entity
#Table(name = "member")
public class Member implements Serializable {
private static final long serialVersionUID = 1871629487715861212L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(name = "first_name")
private String firstName;
#Column(name = "last_name")
private String lastName;
#Column(name = "ident_doc")
private String identDoc;
#Column(name = "join_date")
private String joinDate;
private String nickname;
#OneToOne(mappedBy = "member")
private MemberContact memberContact;
#OneToMany(mappedBy = "member", cascade = CascadeType.ALL)
private List<MemberChapterLog> memberChapterLogs;
#OneToMany(mappedBy = "member")
private List<ChapterOfficers> chapterOfficers;
#OneToOne(mappedBy = "contactMember", cascade = CascadeType.ALL)
private Chapter asChapterContact;
Chapter:
#Entity
#Table(name = "chapter")
#NamedQuery(
name = "Chapter_Get_Detailed_Members_List",
query = "from MemberChapterLog where chapter.id = :paramChapter and active = true "+
"order by member.lastName asc")
public class Chapter implements Serializable {
private static final long serialVersionUID = -8387387246818721664L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String initials;
#Column(name ="chap_name")
private String chapName;
#ManyToOne
#JoinColumn(name = "category")
private ChapCategory category;
#OneToOne
#JoinColumn(name = "contact_member")
private Member contactMember;
#OneToOne(mappedBy = "chapter", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private ChapterContact chapterContact;
#OneToMany(mappedBy = "chapter")
private List<MemberChapterLog> memberChapterlogs;
#OneToMany(mappedBy = "chapter")
private List<ChapterOfficers> chapterOfficers;
MemberChapterLog:
#Entity
#Table(name = "member_chapter_log")
public class MemberChapterLog implements Serializable {
private static final long serialVersionUID = -643503606583240644L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "member_id")
private Member member;
#ManyToOne
#JoinColumn(name = "chapter_id")
private Chapter chapter;
#Column(name = "log_date")
private String logDate;
private String comment;
private boolean active;
I want to get a list of the active members of certain chapter (passed as ':paramChapter'), order by their last name. When I run the named query at chapter ("from MemberChapterLog where chapter.id = :paramChapter and active = true order by member.lastName asc") it generates the following error:
org.hibernate.HibernateException: Errors in named queries:
Chapter_Get_Detailed_Members_List failed because of: org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected token: member near line 1, column 105 [from dev.xarlsr.cdt.entity.MemberChapterLog where chapter.id = :paramChapter and active = true order by member.lastName asc]
If I delete the order by member.lastName it works properly (without any order, byt the way).
I tried to change the mapping by changing the tables foreign keys and the ownership, but doesn't work. I tried to change the fetch type without results. What am I doing wrong?

The problem is the mapping:
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "member_id")
private Member member;
member is a keyword in JPQL/HQL and soft-keyword handling was only introduced in Hibernate 6, so you will need to change the name of the field to e.g. memberAssociation and the query condition to ... order by memberAssociation.lastName asc

Related

How do I retrieve parent object with child object while having OneToMany bidriectional relationship in spring boot?

I am new to Spring boot. please help me with the below issue:
I am getting only child object data while retrieving using join query..
Below is my child entity class:
#Entity
#Table(name = "tenant_user_configuration")
public class TenantUserConfiguration {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(name = "config_key")
private String configKey;
#Column(name = "config_value")
private String configValue;
private String system;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="tenant_user_id",referencedColumnName = "tenant_user_id")
#JsonBackReference
private TenantUser tenantUser;
This is my parent entity class:
#Entity
#Table(name = "tenant_user")
public class TenantUser {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "tenant_user_id")
private int tenantUserId;
#OneToOne
#JoinColumn(name = "tenant_id",referencedColumnName = "tenant_id")
private Tenant tenant;
#Column(name = "user_name")
private String userName;
#Column(name = "password")
private String password;
#Column(name = "enabled")
private boolean enabled;
#OneToMany(mappedBy = "tenantUser",fetch = FetchType.EAGER)
#JsonManagedReference
private Set<TenantUserConfiguration> tenantUserConfiguration = new HashSet<>();

org.hibernate.PropertyAccessException: Could not set field value [STRING] value by reflection for String

Does the #Embeddable for #ManyToMany relations and additional columns, works with String?
I do not use #Generated Value for #Id
Because my Entity ApplikationUser
#Id
#Column(length = 128)
private String applikationUserId;
by business logic has always an Id
Here my code:
#EmbeddedId
private ApplikationUserPopupMessageId applikationUserPopupMessageId;
#ManyToOne(fetch = FetchType.EAGER)
#MapsId("applikationUserId")
private ApplikationUser applikationUser;
#ManyToOne(fetch = FetchType.EAGER)
#MapsId("popupMessageId")
private PopupMessage popupMessage;
#Column(name = "gelesen")
private boolean gelesen = false;
#Embeddable
public class ApplikationUserPopupMessageId implements Serializable {
#Column(name = "applikation_user_id")
private String applikationUserId;
#Column(name = "popup_message_id")
private Long popupMessageId;
#Entity
#Table
public class PopupMessage {
#Id
#GeneratedValue
#Column(length = 128)
private Long messageId;
private String title;
private String message;
#OneToMany(
mappedBy = "applikationUser",
cascade = CascadeType.ALL,
orphanRemoval = true
)
private List<ApplikationUserPopupMessage> applikationUserPopupMessages = new ArrayList<>();
#Entity
public class ApplikationUser implements UserDetails {
/**
*
*/
private static final long serialVersionUID = -5517804528054972083L;
#Id
#Column(length = 128)
private String applikationUserId;
#Column
private String password;
#ManyToOne
#JoinColumn(name = "idRole")
private Role role;
private boolean enabled = true;
#OneToMany(
mappedBy = "popupMessage",
cascade = CascadeType.ALL,
orphanRemoval = true
)
private List<ApplikationUserPopupMessage> applikationUserPopupMessages = new ArrayList<>();
EDIT - 23.11.2020
Regards the lack of interest, its seems to be possible to us #Embeddable with String?
Instantiate applikationUserPopupMessageId:
#Entity
public class ApplikationUserPopupMessage {
#EmbeddedId
private ApplikationUserPopupMessageId applikationUserPopupMessageId = new ApplikationUserPopupMessageId();
}
That's known issue
Just put getters and setters for the according properties in your #Embeddable.
Does it help if you annotate your entity class with Access level to Field
#Entity(access = AccessType.FIELD)

Hibernate unable to map many students to a class

I hae 2 simple entities: Student and Class. I want to POST a student, where I specify the class it belongs to, but I've got stuck in hibernate mapping.
ClassModel.class
#Entity
#Table(name = "class" )
public class ClassModel implements Serializable {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#NotEmpty
#Size(max = 20)
#Column(name = "name")
private String name;
#Column(name = "tables")
private int tables;
#Column(name = "chairs")
private int chairs;
#Column(name = "teacher")
private String teacher;
(getters + setters)
StudentModel
#Entity
#Table(name = "student")
public class StudentModel implements Serializable {
#Id
#Column(name = "student_id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int student_id;
#NotEmpty
#Column(name = "name")
#Size(max = 50)
private String name;
#Column(name = "age")
private int age;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "id")
private ClassModel classModel;
(getters + setters)
}
StudentController.java
...
#Autowired
private StudentService studentService;
#Autowired
private ClassService classService;
#PostMapping(value = "/save")
public StudentModel save(#RequestBody StudentModel studentModel){
ClassModel classModel = classService.findById(studentModel.getClassId()).get();
studentModel.setClassModel(classModel);
return studentService.save(studentModel);
}
...
But when I make a request from Postman with the following body:
{
"name": "some name",
"age": 12,
"class_id": 1
}
I get the following error from hibernate:
Column 'class_id' cannot be null
Where is the mistake in my hibernate mapping?
It's how I have made working join in hibernate. Have a look:
TrainingEntity.java
#Id
private Integer id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "animal_id", nullable = false, insertable = false, updatable = false)
private AnimalEntity animalEntity;
#Column(name = "animal_id")
private Integer animalId;
AnimalEntity.java
#Id
private Integer id;
#OneToMany(mappedBy = "animalEntity", fetch = FetchType.LAZY)
private List<TrainingEntity> trainingEntityList = new ArrayList<>();
So here is the join between AnimalEntity and TrainingEntity.
AnimalEntity have a list of TrainingEntities.
The mistake is in this line:
"class_id": 1
You're using column name instead of field name. You would have to replace class_id with classModel, where classModel would be an object. Other solution would be to find ClassModel by id from json and set it as parent to StudentModel.

Java Hibernate Database speed issue

I generated application using Jhipster. In start everything was working fine but as application grow tournament entity become issue regarding performances.
This is my entity :
/**
* A Tournament.
*/
#Entity
#Table(name = "tournament")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
#Document(indexName = "tournament")
public class Tournament implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
#SequenceGenerator(name = "sequenceGenerator")
private Long id;
#Column(name = "name")
private String name;
#Column(name = "location")
private String location;
#Column(name = "url")
private String url;
#Column(name = "start_date")
private ZonedDateTime startDate;
#Column(name = "end_date")
private ZonedDateTime endDate;
#Column(name = "entry_fee")
private Double entryFee;
#Column(name = "prize")
private Double prize;
#Column(name = "goods")
private String goods;
#Column(name = "favorite_rating")
private Long favoriteRating;
#Column(name = "participants_number")
private Integer participantsNumber;
#Column(name = "finished")
private Boolean finished;
#Column(name = "view_only")
private Boolean viewOnly;
#Column(name = "image")
private String image;
#Column(name = "description")
private String description;
#Column(name = "teams_applied")
private String teamsApplied;
#Lob
#Column(name = "schedule")
private String schedule;
#Lob
#Column(name = "prize_distribution")
private String prizeDistribution;
#Lob
#Column(name = "contacts")
private String contacts;
#Lob
#Column(name = "rules")
private String rules;
#OneToMany(mappedBy = "tournament", fetch = FetchType.LAZY)
#JsonIgnore
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
private Set<Stream> streams = new HashSet<>();
#ManyToMany
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
#JoinTable(name = "tournament_platforms", joinColumns = #JoinColumn(name = "tournaments_id", referencedColumnName = "id"), inverseJoinColumns = #JoinColumn(name = "platforms_id", referencedColumnName = "id"))
private Set<Platform> platforms = new HashSet<>();
#ManyToMany(mappedBy = "favoriteTournaments", fetch = FetchType.LAZY)
#JsonIgnore
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
private Set<User> favoriteUsers = new HashSet<>();
#ManyToOne
private Game game;
#ManyToOne
private TournamentStatus status;
#ManyToOne
private EntryType entryType;
#ManyToOne
private TournamentFormat format;
#ManyToOne
private Region region;
#ManyToOne
private GameMode gameMode;
#ManyToOne
private PrizeType prizeType;
#ManyToOne
private Organizer organizer;
#ManyToOne
private TournamentStage stage;
#ManyToOne
private HostPlatform hostPlatforms;
#ManyToOne
private TournamentType type;
#ManyToOne
private PlayType playType;
#ManyToOne
private Currency currency;
#ManyToOne
private Country country;
I am using spring JPA. Getting 20 tournaments from database takes 39 seconds. That is not acceptable. Is there any way i can reduce it to normal speed. What is reason for such a long response time ? Every many to one relation i made unidire
In hibernate's implementation of JPA, #ManyToOne has a fetchType = EAGER by default and you have 14 of them.
#ManyToOne
private Country country;
That means 14 joins for each request. I highly recommend to use fetchType = LAZY for all relationships and deactivate them one by one when needed.
As a rule of thumb, you should not use more than 3 joins per request.
Also take a look at the generated request and use EXPLAIN PLAN in order to understand what the database really does and where it is costly. It will probably reveal some missing indexes on columns used as foreign keys...

how to resolve the 'save transient instance before saving' error on one to many relationship in hibernate jpa

this is the parent entity this is the child entityi have tried the suggested solution to similar error above but my application still spits out the same exception. please i need help
below is the exception
org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing: com.domkat.springmvcjpa.model.Cpfaceleft1angle.cpftid -> com.domkat.springmvcjpa.model.Fromtocp
at org.hibernate.engine.spi.CascadingAction$8.noCascade(CascadingAction.java:380)
at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:177)
at org.hibernate.event.internal.AbstractFlushingEventListener.cascadeOnFlush(AbstractFlushingEventListener.java:162)
at org.hibernate.event.internal.AbstractFlushingEventListener.prepareEntityFlushes(AbstractFlushingEventListener.java:153)
at org.hibernate.event.internal.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:89)
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1234)
at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:404)
at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.beforeTransactionCommit(JdbcTransaction.java:101)
at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:175)
at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:75)
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:515)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:757)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:726)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:478)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:272)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
at com.sun.proxy.$Proxy626.save(Unknown Source)
#Entity
#Table(name = "cpobservedhorizontalangles")
public class Cpobservedhorizontalangles implements Serializable {
private static final long serialVersionUID = 1L;
#Column(name = "degree")
private Integer degree;
#Column(name = "minute")
private Integer minute;
#Column(name = "second")
private Integer second;
#Column(name = "degminsec")
private String degminsec;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "ohaid")
private Integer ohaid;
#OneToMany(cascade={CascadeType.ALL},mappedBy = "ohaid")
private List<Cpfaceleft2angle> cpfaceleft2angleList;
#OneToMany(cascade={CascadeType.ALL},mappedBy = "ohaid")
private List<Cpfaceright2angle> cpfaceright2angleList;
#OneToMany(cascade={CascadeType.ALL},mappedBy = "ohaid")
private List<Cpfaceleft1angle> cpfaceleft1angleList;
#OneToMany(cascade={CascadeType.ALL},mappedBy = "ohaid")
private List<Cpfaceright1angle> cpfaceright1angleList;
...getters and setters... this is the child entity
#Entity
#Table(name = "cpfaceleft1angle")
public class Cpfaceleft1angle implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "id")
private Integer id;
#OneToMany(cascade={CascadeType.PERSIST},mappedBy = "cpfl1id")
private List<Fromtocp> fromtocpList;
#JoinColumn(name = "ohaid", referencedColumnName = "ohaid")
#ManyToOne
private Cpobservedhorizontalangles ohaid;
#JoinColumn(name = "faceid", referencedColumnName = "faceid")
#ManyToOne
private Faceleft faceid;
...getters and setters... this is the parent class but it contains other
entities
public class Fromtocp implements Serializable {
private static final long serialVersionUID = 1L;
// #Max(value=?) #Min(value=?)//if you know range of your decimal fields consider using these annotations to enforce field validation
#Column(name = "distance")
private Double distance;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "ftcpid")
private Integer ftcpid;
#Column(name = "diffleft")
private String diffleft;
#Column(name = "diffright")
private String diffright;
#Column(name = "meandiff")
private String meandiff;
#Column(name = "oadegdec")
private Double oadegdec;
#Column(name = "fb")
private Double fb;
#Column(name = "bb")
private Double bb;
#JoinColumn(name = "fromcp", referencedColumnName = "cpid")
#ManyToOne
private Controlpoints fromcp;
#JoinColumn(name = "cpfl1id", referencedColumnName = "id")
#ManyToOne
private Cpfaceleft1angle cpfl1id;
#JoinColumn(name = "cpfl2id", referencedColumnName = "id")
#ManyToOne
private Cpfaceleft2angle cpfl2id;
#JoinColumn(name = "cpfr1id", referencedColumnName = "id")
#ManyToOne
private Cpfaceright1angle cpfr1id;
#JoinColumn(name = "cpfr2id", referencedColumnName = "id")
#ManyToOne
private Cpfaceright2angle cpfr2id;
#JoinColumn(name = "tocp", referencedColumnName = "cpid")
#ManyToOne
private Controlpoints tocp;
...this is the other entity the parent class contains.
#Controller
public class SurveyController {
#Autowired
private SurveyService ss;
#Autowired
private ControlPointService cps;
#Autowired
private ScpService sps;
#Autowired
private CpobservedhorizontalanglesService cpos;
#Autowired
private Cpfaceleft1angleService cpfl1;
#Autowired
private Cpfaceleft2angleService cpfl2;
#Autowired
private Cpfaceright1angleService cpfr1;
#Autowired
private Cpfaceright2angleService cpfr2;
#Autowired
private FromTocpService ftcps;
#Autowired
private FaceleftService fls;
#Autowired
private FacerightService frs;
private Processor processor = new Processor();
HttpSession session;
#RequestMapping(value = "/surveydetails")
public String showSurveyDetailsPage(Model model) {
Surveys survey = new Surveys();
model.addAttribute("survey", survey);
return "SurveyDetails";
}
#RequestMapping(value = "/stations", method = RequestMethod.POST)
public String createSurvey(#RequestParam("surveyTitle") String title,
#RequestParam("cp1Label") String cp1Label, #RequestParam("cp1Northings") double northingsCp1,
#RequestParam("cp1Eastings") double eastingsCp1, #RequestParam("cp2Label") String cp2Label,
#RequestParam("cp2Northings") double northingsCp2, #RequestParam("cp2Eastings") double eastingsCp2,
#RequestParam("distance") double distance, #RequestParam("fl1Deg") int fl1Deg,
#RequestParam("fl1Min") int fl1Min, #RequestParam("fl1Sec") int fl1Sec,
#RequestParam("fl2Deg") int fl2Deg, #RequestParam("fl2Min") int fl2Min, #RequestParam("fl2Sec") int fl2Sec,
#RequestParam("fr1Deg") int fr1Deg, #RequestParam("fr1Min") int fr1Min, #RequestParam("fr1Sec") int fr1Sec,
#RequestParam("fr2Deg") int fr2Deg, #RequestParam("fr2Min") int fr2Min, #RequestParam("fr2Sec") int fr2Sec) {
Surveys survey = new Surveys();
Scp scp = new Scp();
Signups su = null;
Cpobservedhorizontalangles o1 = new Cpobservedhorizontalangles();
o1.setDegree(fl1Deg);
o1.setMinute(fl1Min);
o1.setSecond(fl1Sec);
o1.setDegminsec(processor.degToString(fl1Deg, fl1Min, fl1Sec));
Cpfaceleft1angle fl1 = new Cpfaceleft1angle();
fl1.setOhaid(o1);
fl1.setFaceid(faceleft1);
cpos.save(o1);
cpfl1.save(fl1);
please help. thanks
i have resolved the problem. And in addition i found out how i can actually save just the parent class by calling the save method on the parent and then it saves the child entities as well. jpa makes it quite easy.
i will use an illustration of employee and address. lets say an employee can have more than one address it means we will have two tables in the database and two entity classes, one for each of these tables right?. it also means that the employee table becomes the parent table while the address becomes the child table right? the code below just shows how you can save the parent class and by the saving the parent class the child entities get saved as well! all you do is set the parent object(in this case the employee) on the child object(in this case the address), then set the List(the list of child in this case is address. so it becomes List) on the parent entity. then call the save method on the parent.
...necessary imports...
#Entity
#Table(name = "address")
#NamedQueries({
#NamedQuery(name = "Address.findAll", query = "SELECT a FROM Address a")})
public class Address implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "address_id")
private Integer addressId;
#Column(name = "employee_address")
private String employeeAddress;
#JoinColumn(name = "employee_id", referencedColumnName = "employee_id")
#ManyToOne
private Employee employeeId;
public Address() {
}
...getters and setters for this entity...
#Entity
#Table(name = "employee")
#NamedQueries({
#NamedQuery(name = "Employee.findAll", query = "SELECT e FROM Employee e")})
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "employee_id")
private Integer employeeId;
#Column(name = "name")
private String name;
#Column(name = "email")
private String email;
#Column(name = "phone")
private String phone;
#OneToMany(cascade=CascadeType.ALL,mappedBy = "employeeId")
private List<Address> addressList;
public Employee() {
}
...getters and setters for this class...
...below is the class that makes use of the entities...
public class SaveExample {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("JPAJoinTableTutorialsPU");
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
Employee employee = new Employee();// employee object
Address address = new Address(); // Address Object
address.setEmployeeAddress("set the value");
address.setEmployeeId(employee);
List<Address>addressList=new ArrayList<>();
addressList.add(address);
employee.setEmail("set the value");
employee.setName("set the value for name");
employee.setPhone("set the value");
employee.setAddressList(addressList);
em.persist(employee);
em.getTransaction().commit();
}
}
i hope that helps some people..thanks

Categories