I'm trying to execute an HQL for a many to many mapping in hibernate and getting a weird issue:
Caused by: java.sql.SQLSyntaxErrorException: Unknown columnallowedage1_.allowedAgencies_organization_id' in 'on clause'
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:120)
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:97)
Basically, I have two tables, Reservation_Reason_Type and Agency. I need to do a many to many before them. I believe I'm doing everything correctly, but when I run the code, its giving me this unknown column issue. Not sure why it is doing allowedage1_allowedAgencies_organization_id. It is including the variable name in generated HQL as well.
Below are the mapped classes:
Agency.java
#Entity
#Table(name = "AGENCY")
public class Agency {
#Id
#Column(name="organization_id")
private int id;
#Column(name="name")
private String name;
#Column(name="acronym")
private String acronym;
#ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "allowedAgencies")
private Collection<ReservationReasonType> allowedReservations = new ArrayList<ReservationReasonType>();
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAcronym() {
return acronym;
}
public void setAcronym(String acronym) {
this.acronym = acronym;
}
public Collection<ReservationReasonType> getAllowedReservations() {
return allowedReservations;
}
public void setAllowedReservations(Collection<ReservationReasonType> allowedReservations) {
this.allowedReservations = allowedReservations;
}
}
ReservationReasonType.java
#Entity
#Table(name = "RESERVATION_REASON_TYPE")
public class ReservationReasonType {
#Id
#Column(name = "reservation_reason_type_id")
private int id;
#Column(name = "description")
private String description;
#Column(name = "reservation_reason_type_code")
private String code;
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(name="RES_AGENCY", joinColumns={#JoinColumn(referencedColumnName="reservation_reason_type_id")}
, inverseJoinColumns={#JoinColumn(referencedColumnName="organization_id")})
private Collection<Agency> allowedAgencies = new ArrayList<Agency>();
public ReservationReasonType(int id, String description, String code) {
this.setId(id);
this.setDescription(description);
this.setCode(code);
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public Collection<Agency> getAllowedAgencies() {
return allowedAgencies;
}
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(name="RES_AGENCY", joinColumns={#JoinColumn(referencedColumnName="reservation_reason_type_id")}
, inverseJoinColumns={#JoinColumn(referencedColumnName="organization_id")})
//Set<Agency> allowedAgencies = new HashSet<Agency>();
public void setAllowedAgencies(Collection<Agency> allowedAgencies) {
this.allowedAgencies = allowedAgencies;
}
}
Below is the query that I'm using for HQL:
String query = "select rrt from ReservationReasonType as rrt join rrt.allowedAgencies age where age.acronym = :agencyAcronym)";
Below is the generated HQL which won't run because of the unknown columns:
Hibernate:
select
reservatio0_.reservation_reason_type_id as reservat1_2_,
reservatio0_.reservation_reason_type_code as reservat2_2_,
reservatio0_.description as descript3_2_
from
RESERVATION_REASON_TYPE reservatio0_
inner join
RES_AGENCY allowedage1_
on reservatio0_.reservation_reason_type_id=allowedage1_.allowedReservations_reservation_reason_type_id
inner join
AGENCY agency2_
on allowedage1_.allowedAgencies_organization_id=agency2_.organization_id
where
agency2_.acronym=?
I double checked whether I'm doing the mapping right, and I think there isn't any issue with that. One thing I'm not sure of is that I'm using Hibernate 3.0, hibernate jpa 2.0, and mysql 8.0.19. Not sure if it can be an issue with that?
Need help.
UPDATE:
For a temporary solution, I added the below two columns to the RES_AGENCY table and its working, but this is just a bandaid. Still trying to figure out what can be a proper solution:
allowedReservations_reservation_reason_type_id
allowedAgencies_organization_id
Related
I want to display on my jsp something like this
CategoryParent1
-----Subcategory1
-----Subcategory2
CategoryParent2
-----Subcategory1
-----Subcategory2
In which way i can solve it? Does spring-mvc has some library for it? Or i must use some external libraries?
I have a Category model
#Entity
public class Category {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
#ManyToOne
private Category parentCategory;
#OneToMany(mappedBy = "parentCategory", cascade = CascadeType.ALL)
private List<Category> childCategories = new ArrayList<>();
public Category() {
}
public Category(String name){
this.name = name;
}
public Category(String name, Category parentCategory) {
this.name = name;
this.parentCategory = parentCategory;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Category getParentCategory() {
return parentCategory;
}
public void setParentCategory(Category parentCategory) {
this.parentCategory = parentCategory;
}
public List<Category> getChildCategories() {
return childCategories;
}
public void setChildCategories(List<Category> childCategories) {
this.childCategories = childCategories;
}
}
I have done the similar task but with recursive query. Here is the
link
If you don't want to use recursive query. here is what you need to do.
Eagerly fetch child categories (see hibernate eager fetch| lazy load)
Remove the "sub query" which is inside the "main query" and remove the recursing statement of a function
If you have successfully created relationship, you can just get its children categories by using your "getchildrencategories" method.
It is your choice whether you use recursive function or not.
And do not use List its better to use Set:
#OneToMany(fetch = FetchType.EAGER, mappedBy="parentCategory", cascade=CascadeType.REMOVE, orphanRemoval=true )
private Set<Categories> childCategories = new HashSet<Categories>();
How do I write the method name for the below query:
#Query("SELECT r.skill, r.rating, count(r) FROM AssociateRating r "
+ "where updatedTime = ( select max(updatedTime) from AssociateRating a "
+ "where r.associate = a.associate ) GROUP BY r.skill, r.rating")
List<Object[]> findCountMostRecent();
Please find below the model:
#Entity
#Table(name = "associate_ratings")
public class AssociateRating {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String associate;
#ManyToOne
#JoinColumn(name = "skill_id")
private Skill skill;
private int rating;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "updated_time")
private Date updatedTime;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getAssociate() {
return associate;
}
public void setAssociate(String associate) {
this.associate = associate;
}
public Skill getSkill() {
return skill;
}
public void setSkill(Skill skill) {
this.skill = skill;
}
public int getRating() {
return rating;
}
public void setRating(int rating) {
this.rating = rating;
}
public Date getUpdatedTime() {
return updatedTime;
}
public void setUpdatedTime(Date updatedTime) {
this.updatedTime = updatedTime;
}
}
/**
* Skill Model
*/
#Entity
#Table(name = "skills")
public class Skill {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
I am getting exception when trying to extract records from associate_ratings
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'updatedTime' in 'where clause'
Could you please advise what is wrong here?
Could you also please let me know how do we name Spring JPA findXX methods in such cases?
Indeed there is no 'updatedTime' column in your table.
The column name is 'updated_time', as shown in your #Entity updatedTime variable.
Now in case you want to create method name using JPA keywords I guess it is not possible in your query for several reasons:
You can't select specific columns (r.skill, r.rating, count(r)), but you should select them all.
You can't have nested queries.
There is no GroupBy keyword
You can find all the JPA supported keywords here: 2.3 Query methods
So in your case, you should go for the #Query approach.
The jhipster doesn't support create many to many relationships with extra fields.
What is the best way to create many to many association with extra columns in jhispter? Should i create a two one-to-many relationship with extra fields?
Using JHipster Domain Language (JDL), a #ManytoMany holding extra properties (columns) can be easily achieved using an association entity and two ManyToOne relationships. See below:
entity Foo{
...
}
entity Bar{
...
}
entity FooBarAssociation{
extraProperty1 String
extraProperty2 String
...
}
relationship ManyToOne {
FooBarAssociation{foo} to Foo{bars}
FooBarAssociation{bar} to Bar{foos}
}
You will have to do it manually.
this post describes how: https://hellokoding.com/jpa-many-to-many-extra-columns-relationship-mapping-example-with-spring-boot-maven-and-mysql/
In general, as #Antares42 said, you should create an entity for the Many-To-Many table like so:
first entity:
#Entity
public class Book{
private int id;
private String name;
private Set<BookPublisher> bookPublishers;
public Book() {
}
public Book(String name) {
this.name = name;
bookPublishers = new HashSet<>();
}
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#OneToMany(mappedBy = "book", cascade = CascadeType.ALL, orphanRemoval = true)
public Set<BookPublisher> getBookPublishers() {
return bookPublishers;
}
public void setBookPublishers(Set<BookPublisher> bookPublishers) {
this.bookPublishers = bookPublishers;
}
}
secound entity:
#Entity
public class Publisher {
private int id;
private String name;
private Set<BookPublisher> bookPublishers;
public Publisher(){
}
public Publisher(String name){
this.name = name;
}
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#OneToMany(mappedBy = "publisher")
public Set<BookPublisher> getBookPublishers() {
return bookPublishers;
}
public void setBookPublishers(Set<BookPublisher> bookPublishers) {
this.bookPublishers = bookPublishers;
}
}
Join table entity:
#Entity
#Table(name = "book_publisher")
public class BookPublisher implements Serializable{
private Book book;
private Publisher publisher;
private Date publishedDate;
#Id
#ManyToOne
#JoinColumn(name = "book_id")
public Book getBook() {
return book;
}
public void setBook(Book book) {
this.book = book;
}
#Id
#ManyToOne
#JoinColumn(name = "publisher_id")
public Publisher getPublisher() {
return publisher;
}
public void setPublisher(Publisher publisher) {
this.publisher = publisher;
}
#Column(name = "published_date")
public Date getPublishedDate() {
return publishedDate;
}
public void setPublishedDate(Date publishedDate) {
this.publishedDate = publishedDate;
}
}
This entity describes the relationship between Book and Publisher and the extra field is published_date
Let's say you have entities like Movie, Rater and needs a join table Ratings. You can write a JDL script like the following:
entity Movie { title String}
entity Rater { name String}
entity Rating { value Integer} //the extra field
relationship ManyToMany {
Rating{rater(name)} to Rater,
Rating{movie(title)} to Movie
}
save it in file.jdl in the project folder, open cmd type
jhipster import-jdl file.jdl
and you have everything
Exception with Spring. When I try to bind my entities to tables with #OneToMany annotation.
Caused by: org.hibernate.AnnotationException: #OneToOne or #ManyToOne
on com.wumf.iModuleSyncApps.impl.IAppEntity.packageName references an
unknown entity: java.lang.String at
org.hibernate.cfg.ToOneFkSecondPass.doSecondPass(ToOneFkSecondPass.java:109)
at
org.hibernate.cfg.Configuration.processEndOfQueue(Configuration.java:1598)
at
org.hibernate.cfg.Configuration.processFkSecondPassInOrder(Configuration.java:1521)
at
org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1422)
at
org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1846)
at
org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:852)
... 41 more
#Entity
#Table(name = "IApp")
public class IAppEntity {
#ManyToOne
#JoinColumn(referencedColumnName="packageName")
#Id
private String packageName;
private String icon;
private String name;
public String getPackageName() {
return packageName;
}
public void setPackageName(String packageName) {
this.packageName = packageName;
}
public String getIcon() {
return icon;
}
public void setIcon(String icon) {
this.icon = icon;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
and
#Entity
#Table(name = "IAppsFriends")
public class IAppsFriends {
#GeneratedValue
#Id
private int id;
#OneToMany(fetch = FetchType.EAGER, mappedBy = "packageName")
private List<IAppEntity> apps;
private String phone;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public List<IAppEntity> getApps() {
return apps;
}
public void setPackageName(List<IAppEntity> apps) {
this.apps = apps;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
}
Also I tried changing #JoinColumn(referencedColumnName="packageName") to
#JoinColumnn(name="packageName") to no avail.
Your #ManyToOne annotation is misplaced. You are annotating a String variable when you should be annotating a IAppsFriends:
#Table(name = "IApp")
public class IAppEntity {
#Id
private String packageName;
#ManyToOne
#JoinColumn(referencedColumnName="packageName")
private IAppsFriends friends;
// ... rest of code
}
You should also change IAppsFriends class to fix the mappedBy attribute:
#OneToMany(fetch = FetchType.EAGER, mappedBy = "friends")
private List<IAppEntity> apps;
If you want to add a OnwToMany relationship from IAppEntity to IAppsFriends, you should store the id of IAppsFriends in the table IApp. The type of IAppsFriends.id is int. So I think you should get a right join column like friends int(11) not null.
Then JPA will depend on the value of column friends to get the instance IAppsFriends.
#Table(name = "IApp")
public class IAppEntity {
#Id
private String packageName;
#ManyToOne
#JoinColumn(referencedColumnName="id")
private IAppsFriends friends;
// ... rest of code
}
PS: referencedColumnName means the reference in anther table. So the value should be id (the value of column friends should be one of the id of IAppsFriends)
Of course the code in IAppsFriends should modified to:
#OneToMany(fetch = FetchType.EAGER, mappedBy = "friends")
private List<IAppEntity> apps;
I have model. there is this part:
model was mapped by jpa annotations.Everywhere I use fetchType = EAGER. If I load vacancy from database, I have 2 duplicates status_for_vacancy objects.
I use property hbm2ddl.auto = update.
If I make new schema of database and fill data, I haven't duplicates status_for_vacancy objects.
It really?
code:
vacancy:
#Entity
#Table(name = "vacancy")
#XmlRootElement(name="vacancy")
public class Vacancy {
private List<VacancyStatus> statusList = new LinkedList<VacancyStatus>();
#OneToMany(mappedBy = "vacancy", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
public List<VacancyStatus> getStatusList() {
return statusList;
}
public void setStatusList(List<VacancyStatus> statusList) {
this.statusList = statusList;
}
}
status_for_vacancy:
#Entity
#Table(name = "status_for_vacancy")
public class StatusForVacancy extends AbstractStatus {
public StatusForVacancy() {
super();
}
public StatusForVacancy(Integer id, String name) {
super(id, name);
}
}
#MappedSuperclass
#XmlRootElement
public abstract class AbstractStatus {
private Integer id;
private String name;
public AbstractStatus() {
super();
}
public AbstractStatus(String name) {
super();
this.name = name;
}
public AbstractStatus(Integer id, String name) {
super();
this.id = id;
this.name = name;
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column (name ="id")
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
#Column(name = "name")
#NotEmpty
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
vacancy_status:
#Entity
#Table(name = "vacancy_status")
public class VacancyStatus extends AbstractHistoryStatus {
private Vacancy vacancy;
private StatusForVacancy status;
public VacancyStatus() {
super();
}
public VacancyStatus(Integer id, User author, Date date,
Vacancy vacancy, StatusForVacancy status) {
super(id, author, date);
this.vacancy = vacancy;
this.status = status;
}
#ManyToOne
#JoinColumn(name = "vacancy_id")
public Vacancy getVacancy() {
return vacancy;
}
public void setVacancy(Vacancy vacancy) {
this.vacancy = vacancy;
}
#ManyToOne
#JoinColumn(name = "status_id")
public StatusForVacancy getStatus() {
return status;
}
public void setStatus(StatusForVacancy status) {
this.status = status;
}
}
#MappedSuperclass
public abstract class AbstractHistoryStatus {
private Integer id;
private User author;
private Date date;
public AbstractHistoryStatus() {
}
public AbstractHistoryStatus(Integer id, User author, Date date) {
super();
this.id = id;
this.author = author;
this.date = date;
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
#ManyToOne
public User getAuthor() {
return author;
}
public void setAuthor(User author) {
this.author = author;
}
#Column(name="creation_date")
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
}
It is all mapping code for these entities.
in debugger:
both id==500 ==> hibernate understand, that it is same objects.
I try add all data from old database to new database - I get old error(
I fix cause of appearance of this problem. It appearances if I add record to note table:
I highly recommend you write equals() and hashCode() methods. The standard equals()/hashCode() implement referential equality (do 2 objects reference the same memory location). So if hibernate has 2 of the 'same' object in memory, but they don't reference the same memory location then you will see the object show up twice. But if you implement equals() based on primary key being equal, then even if there are two copies of the same object in memory, Hibernate won't give you duplicates.
See the JPA spec:
2.4 Primary Keys and Entity Identity
Every entity must have a primary key. ... The value of its primary key
uniquely identifies an entity instance within a persistence context
and to EntityManager operations
Also see this SO post.