New to Hibernate and HQL in general. I have these following entities.
Employee entity
public class Employee implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#Column
private Integer authority;
#Column
private String username;
#Column(name = "user_password")
private String password;
#Column
private String title;
#OneToOne
#JoinColumn(name = "person_id", referencedColumnName = "id")
private Person person;
#Column
private Integer gender;
#Column
private String ssn;
#Column(name = "car_info")
private String carInfo;
#Column(name = "birth_date")
private Date birthDate; //java.util Date vs java.sql.Date?
#OneToOne
#JoinColumn(name = "visa_status_id", referencedColumnName = "id")
private VisaStatus visaStatus;
#Column(name = "license_number")
private Integer licenseNumber;
#Column(name = "license_expiration_date")
private Date licenseExpirationDate;
#ManyToOne
#JoinColumn(name = "housing_id", referencedColumnName = "id")
private House house;
}
Person entity
public class Person implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#Column(name = "first_name")
private String firstName;
#Column(name = "last_name")
private String lastName;
#Column(name = "middle_name")
private String middleName;
#Column(name = "preferred_name")
private String preferredName;
#ManyToOne
#JoinColumn(name = "address_id", referencedColumnName = "id")
private Address address;
#Column
private String email;
#Column(name = "ceil_phone")
private String ceilPhone;
#Column(name = "work_phone")
private String workPhone;
}
House entity
public class House implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#OneToOne
#JoinColumn(name = "address_id", referencedColumnName = "id")
private Address address;
#ManyToOne
#JoinColumn(name = "contact_id")
private Contact contactHR;
#ManyToOne
#JoinColumn(name = "landlord_id")
private Person landlord;
}
I'm trying to run this HQL:
select person from Employee where house.id=:houseId
I'm basically trying to get all the Person with the houseId from the Employee. Since I'm trying to only get the person, I'm using the select cause.
But I'm getting these errors:
org.hibernate.hql.internal.ast.InvalidPathException: Invalid path: 'house.id'
org.hibernate.hql.internal.ast.QuerySyntaxException: Invalid path: 'house.id' [select person from example.project.domain.entity.Employee where house.id=:houseId]
I tried the HQL without the select clause and it worked:
from Employee where house.id=:houseId
But I only need person so I didn't want to get everything. Any idea what's wrong?
You asked
Hibernate Invalid Path Exception using HQL
The problem lies on the written query
select person from Employee where house.id=:houseId
Which should contain proper referencing
select p.person from Employee p where p.house.id=:houseId
Why ?
The FROM clause defines which entities the data is going to be selected. Hibernate, or any other JPA implementation, maps the entities to the according database tables and the syntax of a JPQL FROM clause is similar to SQL and indeed uses the entity model for referencing database attributes, which in root query execution (same thing you are doing) one must use the same referencing strategy, which in your case is to use aliases, as A.Panfilov said in comments regardless of hibernate, even in aliasing in SQL is a good practice.
You may find more in here.
Related
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
Using Hibernate, I have created two entities - Employee and EmployeeDetails. Since EmployeeDetails cannot exist without a corresponding entry in Employee, I figured I don't need an extra ID for EmployeeDetails, but could instead use the ID of the Employee entity. Here is how I have implemented this idea:
Employee-Entity:
#Entity
#Table(name = "employees")
#Data
public class Employee {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "employee_id")
private Long id;
#Column(name = "first_name", nullable = false)
private String firstName;
#Column(name = "last_name", nullable = false)
private String lastName;
#OneToOne(cascade = CascadeType.ALL)
EmployeeDetails employeeDetails;
}
Employee-Details-Entity:
#Entity
#Table(name = "employee_details")
#Data
public class EmployeeDetails {
#Id
private Long id;
#Column(name = "address")
private String address;
#Column(name = "e_mail", nullable = false)
private String eMail;
#Column(name = "phone")
private String phone;
#MapsId
#OneToOne(mappedBy = "employeeDetails", cascade = CascadeType.ALL)
#JoinColumn(name = "employee_id")
private Employee employee;
}
By adding the #MapsId annotation to the employee-variable inside EmployeeDetails, I should be assigning the primary key of the Employee-entity to the Id-column of EmployeeDetails.
In a second step, I have written some data into both of my tables.
employee table in MySQL database:
employee_id first_name last_name employee_details_employee_id
1 John Smith null
2 Jennifer Adams null
The last column was somehow generated by Hibernate. I don't understand why. It appears to be some column for identification, but I don't need it.
employee_details table in MySQL database:
employee_id address e_mail phone
1 null john.smith#gmail.com null
2 null jennifer.adams#gmail.com null
I have only assigned an e-mail to the employees. Surprisingly, there is no employee-entry in this database table. I don't really need it anyways, but I was expecting it. So yeah, I think I am doing something terribly wrong and would really appreciate some help.
Change mappedBy side, here useful links
https://vladmihalcea.com/change-one-to-one-primary-key-column-jpa-hibernate/
https://vladmihalcea.com/the-best-way-to-map-a-onetoone-relationship-with-jpa-and-hibernate/
https://javabydeveloper.com/one-one-bidirectional-association/
#Entity
#Table(name = "employees")
#Data
public class Employee {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "employee_id")
private Long id;
#Column(name = "first_name", nullable = false)
private String firstName;
#Column(name = "last_name", nullable = false)
private String lastName;
#OneToOne(mappedBy = "employee", cascade = CascadeType.ALL)
EmployeeDetails employeeDetails;
}
Entity
#Table(name = "employee_details")
#Data
public class EmployeeDetails {
#Id
private Long id;
#Column(name = "address")
private String address;
#Column(name = "e_mail", nullable = false)
private String eMail;
#Column(name = "phone")
private String phone;
#MapsId
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "employee_id")
private Employee employee;
}
#MapId is not a popular solution in work with Hibernate.
Maybe in your case, #Embeddable will be a better option?
If I understand correctly, EmployeeDetails cannot exist without correlated Employee. So, EmployeeDetails could be a field in Employee as an embeddable field:
#Entity
#Table(name = "employees")
#Data
public class Employee {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "employee_id")
private Long id;
#Column(name = "first_name", nullable = false)
private String firstName;
#Column(name = "last_name", nullable = false)
private String lastName;
#Embedded
EmployeeDetails employeeDetails;
}
Then EmployeeDetails doesn't need ID and relation with the employee:
#Embeddable
public class EmployeeDetails {
#Column(name = "address")
private String address;
#Column(name = "e_mail", nullable = false)
private String eMail;
#Column(name = "phone")
private String phone;
}
As you can see, now in the database it's only one table employees, but in our hibernate model, we have two separated objects. Probably you don't need EmployeeDetails without Employee entity, so there is more efficient construction.
If you really need a separated table for EmployeeDetails with relation to Employee I recommend creating standard one-to-one mapping instead of #MapId construction.
I'm creating a MySQL database as followed :
database design
the Country and Province tables are pre-filled with data. I have the application running and can get stuff no problem, and also the join table person_has_address works when getting.
however, when I insert data using post I want to be able to set the ID of the province, and let spring data jpa just add that number to add_pro_id in the Address table. For example, when I post the following json:
{ "firstName":"bilbo", "lastName":"baggings", "address":{"street":"streetName", "streetNum":3, "zipcode":"1337GG", "city":"TheCity", "province":{"name":"aProvinceName"}} }
jpa should see that aProvinceName exists and grab that id and add that to add_pro_id.
Now it just insert aProvinceName as new value in province and add the new id to add_pro_id.
The person class:
#Entity
public class Person {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="per_id")
private int id;
#Column(name="per_name")
private String firstName;
#Column(name="per_surname")
private String lastName;
#Column(name="per_birth_date")
private String birthDate;
#Column(name="per_fax")
private String fax;
#Column(name="per_phone")
private String phone;
#Column(name="per_email")
private String email;
#OneToOne(optional = false, cascade = CascadeType.ALL)
#JoinTable(name="person_has_address", joinColumns = {#JoinColumn(name="pha_per_id", referencedColumnName = "per_id")}, inverseJoinColumns = {#JoinColumn(name="pha_add_id", referencedColumnName = "add_id")})
private Address address;
// getters and setters
This is the person repository:
#RepositoryRestResource(collectionResourceRel = "people", path = "people")
public interface PersonRepository extends PagingAndSortingRepository<Person, Long> {
List<Person> findByLastName(#Param("name") String name);
}
This is the address class:
#Entity
public class Address {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="add_id")
private int id;
#Column(name = "add_street")
private String street;
#Column(name="add_street_num")
private int streetNum;
#Column(name="add_zip")
private String zipcode;
#Column(name="add_city")
private String city;
#JoinColumn(name="add_pro_id", referencedColumnName = "pro_id")
#ManyToOne(optional=false, cascade = CascadeType.ALL)
private Province province;
// getters and setters
Province class:
#Entity
public class Province {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="pro_id")
private int id;
#Column(name="pro_name")
private String name;
#ManyToOne
#JoinColumn(name="pro_cou_id")
private Country country;
// getters and setters
And lastly country class:
#Entity
public class Country {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="cou_id", insertable = false, updatable = false)
private int id;
#Column(name="cou_name", insertable = false, updatable = false)
private String name;
// getters and setters
I've tried adding insertable = false and updatable = false, but the application then just inserts NULL values in my database. I've also tried working with #primarykeyjoins, but to no success.
if anyone knows how I should tackle this problem I would much appreciate it!
Thanks in advance.
I just cannot get the relationship working between my two classes mapped to SQL tables with Hibernate.
The Role class:
#Entity
#Table(name = "role")
public class Role {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="id")
private int id;
#Column(name="name")
private String name;
#OneToMany(mappedBy="memberinfo")
private Set<Memberinfo> members;
...
}
And the Memberinfo class:
#Entity
#Table(name = "memberinfo")
public class Memberinfo {
#Id #GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="id", nullable = false)
private int id;
#Column(name = "userid", nullable = false)
private String userid;
#Column(name = "email", nullable = false)
private String email;
#Column(name = "password", nullable = false)
private String password;
#Column(name = "salt", nullable = false)
private String salt;
#Column(name = "name", nullable = false)
private String name;
#Column(name = "address")
private String address;
#Column(name = "phonenum")
private String phonenum;
#ManyToOne(targetEntity=Role.class)
#JoinColumn(name="role_id")
private Role role;
...
}
When i try to fetch data from the DB, it connects, but throws an exception:
"HTTP Status 500 - #OneToOne or #ManyToOne on model.Memberinfo.role references an unknown entity: model.Role".
If i delete the variable "Role", then it works, and i can fetch the membership data, but i need the connection between the two tables, but in this case, the previously mentioned exception appears every time.
No other solutions on stackoverflow worked for me so far.
Any idea what am i doing wrong?
The "unknown entity error" can be thrown if the class is not actually an Entity (not annotated whith javax.persistence #Entity) or if the persitence provider doesn't "know" the class (package not scanned).
Is the Role class imported in Memberinfo the correct one ? Maybe you are importing another Role class from another library.
This is my entity class Author
#Entity
#Column(name = "ID")
private Long id;
#Column(name = "LAST1")
private String last;
#Column(name="FIRST1")
private String first;
#Lob
#Column(name = "BIO")
private String bio;
#OneToOne
private AuthorDetail authorId;
getters and setters & zero parameter constructor
this is my other entity AuthorDetail here i have mapped using #OneToOne(optional = false,mappedBy = "authorDetail")
#Column(name = "ID")
private Long id;
#Column(name = "ADDRESS1")
private String address1;
#Column(name="ADDRESS2")
private String address2;
#Column(name = "CITY")
private String city;
#Column(name = "STATE1")
private String state;
#Column(name = "ZIP")
private String zip;
#Column(name = "START_DATE")
#Temporal(TemporalType.DATE)
private Date startDate;
#Lob
#Column(name = "NOTES")
private String notes;
#OneToOne(optional = false,mappedBy = "authorDetail")
private Author authorId;
getters and setters
this my main class
`EntityTransaction entr=em.getTransaction();
entr.begin();
Author author=new Author();
author.setFirst("MD");
author.setLast("RAHMATH");
author.setBio("A Software Developer");
Set detailSet=new HashSet<AuthorDetail>();
AuthorDetail detail=new AuthorDetail();
detail.setAddress1("Address1");
detail.setAddress2("Address2");
detail.setCity("NoMansLand");
detail.setState("ZZ");
detail.setZip("12345");
detail.setNotes("This is test detail");
detailSet.add(detail);
em.persist(author);
entr.commit();`
i am getting exceptions if i try run the program
If you want a single-directional relation, you don't need to write #OneToOne in both class.
From the given piece of code, it appears that you want the bi-direction relationship between Author detail and Author.
For the other side to be aware of the relation (bidirectional), it is required to add the mappedBy attribute to the #OneToOne annotation. This attribute references the (Java) property in the entity that is the owner of the relationship. In your case, in AuthorDetail class you need to add;
#OneToOne(optional = false,mappedBy = "authorId")
private Author authorId;
In mappedBy property, you need to give reference to the entity not class name.
In your Author change the following:
#OneToOne
private AuthorDetail authorId;
To:
#OneToOne
private AuthorDetail authorDetail;