INNER JOINs using hibernate - java

I have two classes Task and TaskComponents. TaskComponents contains a task mapped by a Task_ID. I am trying to select a task joined to the TaskComponents table. I have tried many different SQL statements but all of them come back with QuerySyntaxException Path Expected to join.
Task POJO
#Entity
#Table(name = "task")
public class Task implements Serializable {
#Id
#Column(name = "ID")
private int Id;
#Column(name = "Name")
private String name;
#Column(name = "Description")
private String description;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "Site_ID")
private Site site;
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 getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Site getSite() {
return site;
}
public void setSite(Site site) {
this.site = site;
}
}
TaskComponents POJO
#Entity
#Table(name = "taskcomponents")
public class TaskComponents implements Serializable {
#Id
#Column(name = "ID")
private int Id;
#Column(name = "VersionName")
private String versionName;
#Column(name = "Live", nullable = false)
#Type(type = "org.hibernate.type.NumericBooleanType")
private boolean live;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "Task_ID")
private Task task;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "Group_ID")
private GroupDB group;
public int getId() {
return Id;
}
public void setId(int Id) {
this.Id = Id;
}
public String getVersionName() {
return versionName;
}
public void setVersionName(String versionName) {
this.versionName = versionName;
}
public boolean isLive() {
return live;
}
public void setLive(boolean live) {
this.live = live;
}
public Task getTask() {
return task;
}
public void setTask(Task task) {
this.task = task;
}
public GroupDB getGroup() {
return group;
}
public void setGroup(GroupDB group) {
this.group = group;
}
}
And my attempted queries.
Query query = session.createQuery("SELECT t FROM Task t INNER JOIN TaskComponents tc ON t.Id=tc.task.Id");
Query query = session.createQuery("SELECT t FROM Task t INNER JOIN TaskComponents tc ON t=tc.task");

You shouldn't use explicitely ON to define the join, Hibernate will infer it from the mapping, just write you query as
SELECT tc.task FROM TaskComponents tc INNER JOIN tc.task
this is what is referred to behind your error message Path expected for join the query expects a property defined path from one entity to another

Related

How to create multiple mapping of one table? (jpa hibernate)

Im creating an application in spring boot. I want to have multiple entity mapping for one table.
one entity retrieve the table without any join and the other entity retrieve the table with join.
This is the table schema:
book : {"id":1, "title":"math1", "author_id":1}
author: {"id":1, "name": "james"}
thank you.
Ive made it.
#MappedSuperclass
public abstract class BookBase<T extends BookBase> {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(unique = true, nullable = false, updatable = false, name = "id")
private Integer id;
#Column(name = "title")
private String title;
public Integer getId() {
return this.id;
}
public T setId(Integer id) {
this.id = id;
return (T) this;
}
public String getTitle() {
return this.title;
}
public T setTitle(String title) {
this. title = title
return (T) this;
}
}
#Entity
#Table
public class Book extends BookBase<Book> {
#Column(name = "author_id")
private Integer authorId;
public Integer getAuthorId() {
return authorId;
}
public void setAuthorId(Integer authorId) {
this.authorId = authorId;
}
}
#Entity
#Table
public class BookJoinAuthor extends BookBase<BookJoinAuthor> {
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "author_id")
private Author author;
public Author getAuthor() {
return author;
}
public void setAuthorId(Author author) {
this.author = author;
}
}
#Entity
#Table
public abstract class Author {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(unique = true, nullable = false, updatable = false, name = "id")
private Integer id;
#Column(name = "name")
private String name;
public Integer getId() {
return this.id;
}
public T setId(Integer id) {
this.id = id;
return (T) this;
}
public String getName() {
return this.name;
}
public T setName(String name) {
this. name = name
return (T) this;
}
}

Hiberate one-to-one annotaion builds wrong sql query

I have a small problem with hibernate query with one-to-one relation
I created 3 entities. In case of one-to-one relation user-to-group it works properly. I use property create in hiberanate config and it creates correct table with correct FK.
Creating record work correct too
MyUser user = new MyUser();
user.setLogin("Mark");
user.setPassword("123456");
MyPresence presence = new MyPresence();
presence.setPresenceId(2);
presence.setUser(user);
session.beginTransaction();
session.save(user);
session.save(presence);
session.getTransaction().commit();
session.close();
if get User by presence it works correct
int id = 2;
MyPresence myPresence = session.load(MyPresence.class, id);
System.out.println(myPresence);
But when I'm try to get presence by user result from database hibernate build wrong sql query
int id = 3;
MyUser myUser = session.load(MyUser.class, id);
System.out.println(myUser);
Generated Hibernate sql:
Hibernate: select myuser0_.id as id1_2_0_, myuser0_.group_id as group_id4_2_0_, myuser0_.login as login2_2_0_, myuser0_.password as password3_2_0_, mypresence1_.id as id1_1_1_, mypresence1_.presence_id as presence2_1_1_, mypresence1_.updated_at as updated_3_1_1_, mypresence1_.user_id as user_id4_1_1_ from users myuser0_ left outer join user_presence mypresence1_ on myuser0_.id=mypresence1_.id where myuser0_.id=?
But I expect to see
on myuser0_.id=mypresence1_.user_id instead of on myuser0_.id=mypresence1_.id
MyUser.java
#Entity
#Table(name = "users")
public class MyUser {
private int id;
private String login;
private String password;
private MyGroup group;
private MyPresence presence;
public MyUser() {
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
#Column(name = "login")
public String getLogin() {
return login;
}
public void setLogin(String login) {
this.login = login;
}
#Column(name = "password")
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
#JoinColumn(name = "group_id")
#OneToOne(cascade = CascadeType.DETACH, fetch = FetchType.LAZY)
public MyGroup getGroup() {
return group;
}
public void setGroup(MyGroup group) {
this.group = group;
}
#OneToOne(cascade = CascadeType.DETACH)
#JoinColumn(name = "id", referencedColumnName = "user_id")
public MyPresence getPresence() {
return presence;
}
public void setPresence(MyPresence presence) {
this.presence = presence;
}
}
MyPresence.java
#Entity
#Table(name = "presence")
public class MyPresence {
private int id;
private MyUser user;
private int presenceId;
private Date updatedAt;
public MyPresence() {
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "user_id", referencedColumnName = "id")
public MyUser getUser() {
return user;
}
public void setUser(MyUser user) {
this.user = user;
}
#Column(name = "presence_id")
public int getPresenceId() {
return presenceId;
}
public void setPresenceId(int presenceId) {
this.presenceId = presenceId;
}
#Column(name = "updated_at")
public Date getUpdatedAt() {
return updatedAt;
}
public void setUpdatedAt(Date updatedAt) {
this.updatedAt = updatedAt;
}

Save an entity and all its related entities in a single save in spring boot

I'm using Spring Boot,REST and JPA to build my application. In app, there are 2 entities with one to many relationship.
Entity 1 :
#Entity
#Table( name = "report")
#JsonIgnoreProperties(ignoreUnknown = true)
public class CustomReport {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "REPORT_SEQ")
#SequenceGenerator(sequenceName = "REPORT_SEQ", allocationSize = 1, name = "REPORT_SEQ")
private Long id;
private String name;
private Long createdBy;
private Timestamp lastModifiedTimestamp;
#OneToMany(mappedBy = "customReport", cascade = CascadeType.ALL)
private Set<CustomReportActivity> customReportActivitySet;
public Set<CustomReportActivity> getCustomReportActivitySet() {
return customReportActivitySet;
}
public void setCustomReportActivitySet(Set<CustomReportActivity> customReportActivitySet) {
this.customReportActivitySet = customReportActivitySet;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Long getCreatedBy() {
return createdBy;
}
public void setCreatedBy(Long createdBy) {
this.createdBy = createdBy;
}
public Timestamp getLastModifiedTimestamp() {
return lastModifiedTimestamp;
}
public void setLastModifiedTimestamp(Timestamp lastModifiedTimestamp) {
this.lastModifiedTimestamp = lastModifiedTimestamp;
}
}
Entity 2:
#Entity
#Table( name = "report_activity")
public class CustomReportActivity {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "REPORT_ACTIVITY_SEQ")
#SequenceGenerator(sequenceName = "REPORT_ACTIVITY_SEQ", allocationSize = 1, name = "REPORT_ACTIVITY_SEQ")
private Long id;
String activityName;
#ManyToOne
#JoinColumn( name="report_id" )
#JsonBackReference
private CustomReport customReport;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getActivityName() {
return activityName;
}
public void setActivityName(String activityName) {
this.activityName = activityName;
}
public CustomReport getCustomReport() {
return customReport;
}
public void setCustomReport(CustomReport customReport) {
this.customReport = customReport;
}
}
And my request JSON is as follows :
{
"name": "test report",
"createdBy" : 129,
"customReportActivitySet": [
{"activityName":"a"},
{"activityName":"b"},
{"activityName":"c"},
{"activityName":"d"},
{"activityName":"e"}
]
}
I want to save both entities in one shot. I've implemented the save functionality in following way:
#RequestMapping(value="/save", method = RequestMethod.POST)
public ResponseEntity<?> addReport(#RequestBody CustomReport customReport) {
return new ResponseEntity<>(customReportService.createCustomReport(customReport), HttpStatus.CREATED);
}
CustomReportService method:
public CustomReport createCustomReport(CustomReport customReport) {
return customReportRepository.save(customReport);
}
CustomRepository:
public interface CustomReportRepository extends CrudRepository<CustomReport, Long> {
}
But I'm getting the constraint violation exception with this:
java.sql.SQLIntegrityConstraintViolationException: ORA-01400: cannot
insert NULL into ("REPORT_ACTIVITY"."REPORT_ID")
Is it possible to save both entities in one save operation?
Please help!
You would have to add a small piece of code which would populate each CustomReportActivity within the CustomReport instance. Only then the persistence provide can successfully perform the cascade save operation:
public CustomReport createCustomReport(CustomReport customReport) {
customReport.getCustomReportActivitySet.forEach((activity) -> {
activity.setCustomReport(customReport);
});
return customReportRepository.save(customReport);
}
The bottom line is that the dependencies have to be set on both sides of the relationship.
Try this sample, in my case it worked as expected, child entities are saved automatically in a single save operation with creating relations to the parent entity:
#Entity
public class Parent {
#Id
private Long id;
#JoinColumn(name = "parentId")
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
private Set<Child> children;
}
#Entity
public class Child {
#Id
private Long id;
private Long parentId;
}

ManyToMany relation Hibernate

Modelling my SpringBoot application, using Hibernate and PostgreSQL as database.
Need help to properly establish relation ManyToMany.
Class News:
#Entity(name = "news")
public class News implements Serializable {
private Long id;
private Date date;
private String text;
private String author;
private Set<HashTag> hashTags = new HashSet<HashTag>(0);
private byte[] image;
public News() {
}
public News(Date date, String text, String author, Set<HashTag> hashTags, byte[] image) {
this.date = date;
this.text = text;
this.author = author;
this.hashTags = hashTags;
this.image = image;
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "news_id")
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#Temporal(TemporalType.DATE)
#DateTimeFormat(pattern = "DD/MM/YYYY")
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
#Lob
#Type(type = "org.hibernate.type.TextType")
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(name = "news_hashTag",
joinColumns = #JoinColumn(name = "news_id"),
inverseJoinColumns = #JoinColumn(name = "hashtag_id"))
public Set<HashTag> getHashTags() {
return hashTags;
}
public void setHashTags(Set<HashTag> hashTags) {
this.hashTags = hashTags;
}
#Lob
public byte[] getImage() {
return image;
}
public void setImage(byte[] image) {
this.image = image;
}
And class HashTag:
#Entity(name = "hashTag")
public class HashTag implements Serializable {
private Long id;
private String name;
private String description;
private Set<News> news = new HashSet<News>(0);
public HashTag() {
}
public HashTag(String name, String description) {
this.name = name;
this.description = description;
}
#Id
#GeneratedValue (strategy = GenerationType.IDENTITY)
#Column(name = "hashtag_id")
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#ManyToMany(cascade = CascadeType.ALL, mappedBy = "hashTags")
public Set<News> getNews() {
return news;
}
public void setNews(Set<News> news) {
this.news = news;
}
When I try save news like this:
Set<HashTag> hashTags = new HashSet<>();
hashTags.add(new HashTag("HashTag 1");
hashTags.add(new HashTag("HashTag 2");
News news = new News();
news.text = "Some text";
news.author = "Some author";
news.date = new Date();
news.hashTags = hashTags;
newsService.save(news);
I'm getting error:
ERROR: null value in column "news_id" violates not-null constraint
Lets see what we have:
On the owning side of the n-m relation:
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(name = "news_hashTag",
joinColumns = #JoinColumn(name = "news_id"),
inverseJoinColumns = #JoinColumn(name = "hashtag_id"))
public Set<HashTag> getHashTags() {
return hashTags;
}
You do not provide the exclusion of null values because documentation specifies:
boolean nullable() default true;
This is wrong for the relationtable as well as the id. You must:
Set the ID to nullable=false.
Set all JoinColumns of the JoinTable to nullable=false.
There is another problem: You make a insert and an update by newsService.save(news);, you specify a Generator for the ID but have no Generator, this is ok in other databases who provide something like a nextval in Oracle. In PostGreSQL you really should use a sequence-field like this:
#Id
#Column(name = "hashtag_id", nullable = false)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "HashTagIDGenerator")
#SequenceGenerator(name = "HashTagIDGenerator", sequenceName = "SEQ_HASHTAG_ID")
Have a good time.

how to write delete query in hibernate for many to many relationship

I have two beans user and virtualdomain
#Entity
#Table(name = "tblUser")
public class User implements Serializable {
private Long id;
private String username;
private String deleteflag;
private Set<VirtualDomain> virtualdomainset;
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.AUTO)
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#Column(name = "username", length = 50, nullable = false)
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
#Column(name = "deleteflag")
public String getDeleteflag() {
return deleteflag;
}
public void setDeleteflag(String deleteflag) {
this.deleteflag = deleteflag;
}
#ManyToMany(targetEntity = VirtualDomain.class, cascade = {CascadeType.PERSIST},fetch=FetchType.EAGER)
#JoinTable(name = "tblUserDomainRel", joinColumns = #JoinColumn(name = "userid"), inverseJoinColumns = #JoinColumn(name = "domainid"))
public Set<VirtualDomain> getVirtualdomainset() {
return virtualdomainset;
}
public void setVirtualdomainset(Set<VirtualDomain> virtualdomainset) {
this.virtualdomainset = virtualdomainset;
}
}
#Entity
#Table(name = "tblVirtualDomain")
public class VirtualDomain {
private Long id;
private String domainname;
private String deleteflag;
private Set<User> userset;
#Id
#JoinColumn(name = "id")
#GeneratedValue(strategy = GenerationType.AUTO)
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#Column(name = "domain_name")
public String getDomainname() {
return domainname;
}
public void setDomainname(String domainname) {
this.domainname = domainname;
}
#Column(name = "deleteflag")
public String getDeleteflag() {
return deleteflag;
}
public void setDeleteflag(String deleteflag) {
this.deleteflag = deleteflag;
}
#ManyToMany(cascade = {CascadeType.ALL},fetch=FetchType.EAGER, mappedBy = "virtualdomainset", targetEntity = User.class)
public Set<User> getUserset() {
return userset;
}
public void setUserset(Set<User> userset) {
this.userset = userset;
}
}
Now when I delete some user i use to set the deleteflag which means that the data remains in the database.
My requirement is that the user whose delete flag is set must be removed from the tblUserDomainRel table so how to write that delete query.
just remove the virtualDomain from the collection on the User and remove the other side for completeness
// on User
public void removeVirtualDomain(VirtualDomain vd){
virtualDomainset.remove(vd);
vd.getUserset().remove(this)
}
this will remove the relationship record. Or to remove a user from all virtual Domains:
// on User
public void removeFromAllVirtualDomains(){
for( VirtualDomain vd : virtualdomainset ){
vd.getUserset().remove(this);
}
virtualDomainset.clear();
}

Categories