I want to do a query(SELECT) with inner join using JPQL.
I'm using hibernate ddl auto to create tables from the entities.
I have 2 entities, they're relacionated among them by many-to-many relationship(One studio can be managed by many managers(user) and one manager(user) can manage many studios).
As you know, for many-to-many relationship, we use an intermediate table to do a "SELECT" with native SQL, but i'm using JPA and JPQL as query lenguage, so my question is: How to do JOIN SELECT between 2 tables relacionated among them by many-to-many relationship?
The entities below are my entities:
Entity 1(Studio):
#Entity
#Table(name = "studio")
public class Studio implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#Column(name = "studio_name", nullable = false)
private String studioName;
/**
* Indicates if the studio is active or inactive in the data base.
*/
#Column(name = "active")
private Boolean active;
/**
* The studio owner is the main manager for a studio.
*/
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "studio_owner", referencedColumnName = "id", nullable = false)
private User studioOwner;
/**
* Represents all the possible managers for this studio.
*/
#ManyToMany(fetch = FetchType.LAZY)
private List<User> studioManagers;
//--Getters and setter below
}
Entity 2(User):
#Entity
#Table(name = "userr")
public class User implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(name = "user_name", nullable = false, unique = true)
private String userName;
#Column(name = "email", nullable = false, unique = true)
private String email;
#Column(name = "password", length = 60)
private String password;
#Column(name = "name")
private String name;
#Column(name = "last_name")
private String lastName;
#Column(name = "user_state", nullable = false)
#Enumerated(EnumType.STRING)
private UserState userState;
/**
* The roles for this user.
*/
#ManyToMany(fetch = FetchType.EAGER)
private List<Role> roles;
public User() {
}
//--Getters and setter below
}
I'm sorry by me English, Im Spanish speaker.
In StudioRepository.java just write one method
List<Studio> findById(Integer id);
this will fetch studio with all the users associated with this studio.
eg:
Studio{
"id": 1,
"studioName": "some",
"studioOwner": [
{
.....
....
},
{
....
}
]
}
Related
Currently I have the following 2 entities with a one to many relationship -
#Data
#Entity
#Table(name = "invoice_line")
#IdClass(InvoiceLinePK.class)
public class InvoiceLineEntity {
#Id
#Column(name = "line_id")
private String lineId;
#Id
#Column(name = "client_id")
private Integer clientId;
#Id
#Column(name = "invoice_id")
private String invoiceId;
#Column(name = "item_id")
private String itemId;
#Column(name = "amount")
private BigDecimal amount;
#ManyToOne
private InvoiceEntity invoice;
}
#Entity
#Table(name = "invoice")
#IdClass(InvoicePK.class)
#Data
public class InvoiceEntity {
#Id
#Column(name = "client_id")
private Integer clientId;
#Id
#Column(name = "invoice_id")
private String invoiceId;
#Column(name = "description")
private String description;
#Column(name = "txn_total_amount")
private BigDecimal txnTotalAmount;
#Column(name = "created_time", updatable = false)
#CreationTimestamp
private Date createdTime;
#Column(name = "updated_time")
#UpdateTimestamp
private Date updatedTime;
#OneToMany(fetch = FetchType.EAGER, orphanRemoval = true, mappedBy = "invoice")
private List<InvoiceLineEntity> invoiceLines;
}
In a case wherein let's say, one of my existing invoice has 3 lines and I receive a request that this particular invoice has been updated and it now has only 1 line instead of the previous 3 (so the other 2 have to be deleted), I would like to create a new Invoice object with this 1 InvoiceLineEntity and then do a invoiceRepository.save(invoice)
I am expecting that the other 2 InvoiceLine records would be automatically deleted because the orphanRemoval flag is enabled.
Can someone tell me how I can achieve this relationship by tweaking the entity relationship structure of the above 2 entities?
Your child entity must be the owner of the relationship, so that the orphans are allowed to be deleted
If you change and add mappedBy to that relation
#OneToMany(fetch = FetchType.EAGER, orphanRemoval = true, mappedBy = "bill")
private List<BillLine> billLines;
Then the BillLine must also hold a reference
public class BillLine {
#Id
#Column(name = "line_id")
private String lineId;
#Id
#Column(name = "company_id")
private Integer companyId;
#Id
#Column(name = "bill_id")
private String billId;
#Column(name = "item_id")
private String itemId;
#Column(name = "amount")
private BigDecimal amount;
#ManyToOne
private Bill bill;
}
Now it will remove the orphans
Also since you have multiple #Id on each entity. Do you know that you have to either declare a composite class or an embeddable class? Without one of those the multiple Ids are not valid.
Edit:
1) My bad mappedBy should be placed inside #OneToMany and not #JoinColumn. I have corrected it in my answer
2) Remove #JoinColumn. It is wrong in your configuration. By default #OneToMany inserts a column in the side of the #ManyToOne which holds the references to the primary table. You can override those default configurations and create a separate table for mappings but then you need the #JoinTable and I don't see any reason for that here.
This here
#JoinColumns(value = { #JoinColumn(name = "company_id", referencedColumnName = "company_id"),
#JoinColumn(name = "bill_id", referencedColumnName = "bill_id") })
definitely does not belong on #OneToMany
The following can be applied to #OneToMany but as said before I don't see any reason to do that and complicate a simple mapping which does not require a separate table.
#JoinTable(joinColumns = #JoinColumn(name = "company_id", referencedColumnName = "company_id"),
inverseJoinColumns = #JoinColumn(name = "bill_id", referencedColumnName = "bill_id") )
Check here for more information Jpa primary key
I have 2 entities User and Venue. One user can have multiple venues. The table looks like this:
user_id is the foreign key in the Venue table.
I am trying to create a query for retrieving all Venues by user_id. This is what I have:
#Override
public List<Venue> findVenueByOwnerId(Long userId) {
return em.createQuery("select v from Venue v where v.user.id = :ownerId", Venue.class)
.setParameter("ownerId", userId)
.getResultList();
}
What am I doing wrong?
EDIT:
These are my mappings:
For User class:
#Entity
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", updatable = false, nullable = false)
private Long id;
private String email;
private String username;
private String password;
private String firstName;
private String lastName;
#OneToMany
#JoinColumn(name = "user_id")
private List<Venue> venues;
For Venue class:
#Entity
public class Venue {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", updatable = false, nullable = false)
private Long id;
private String name;
private String location;
private int capacity;
#ManyToOne
#Column(name = "user_id", updatable = false, nullable = false)
private User user;
And if I am trying to add getters and setters for the User in the Venue class, it throws me this error:
Caused by: org.hibernate.MappingException: Could not determine type for: razvan.sem3.project.model.User, at table: Venue, for columns: [org.hibernate.mapping.Column(user)]
I have 2 tables project and employee have multiple relationship. Project has many employees, employee can join many projects( many to many). project have one employee whose is team leader, an employee can manager many projects(many to one). So how do I design database, and classes model mapping with database. Some one help me
This is my code
class user
#Entity(name = "USERS")
public class Users {
#Id
#Column(name = "USER_ID", length = 6)
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer userId;
#Column(name = "USER_NAME", length = 50, nullable = false)
private String userName;
#Column(name = "PASS_WORD", length = 50, nullable = false)
private String passWord;
#Column(name = "FULL_NAME", length = 50, nullable = false)
private String fullName;
#Column(name = "EMAIL", length = 50, nullable = false)
private String email;
#Column(name = "PHONE", length = 11, nullable = true)
private String phone;
#Column(name = "STATUS", nullable = true)
private Boolean status;
#ManyToMany(fetch = FetchType.LAZY)
#JsonIgnore
#JoinTable(name = "USERPROJECT", joinColumns = { #JoinColumn(name =
"USER_ID") }, inverseJoinColumns = {
#JoinColumn(name = "PROJECT_ID") })
private List<Project> projects;
#OneToMany(mappedBy = "teamlead")
private List<Project> projectOfTeamLead;
//get set.....
}
class project
#Entity(name = "PROJECTS")
public class Project {
#Id
#Column(name = "PROJECT_ID", length = 6)
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer projectId;
#Column(name = "PROJECT_NAME", length = 50, nullable=false)
private String projectName;
#Column(name = "USER_CREATE_ID", length = 6, nullable=false)
private Integer userCreateId;
// #Column(name = "TEAM_LEAD_ID", length = 6, nullable=false)
// private Integer teamLeadId;
#Column(name = "TIME_START", nullable=true)
private Date timeStart;
#Column(name = "TIME_END", nullable=true)
private Date timeEnd;
#ManyToMany(mappedBy = "projects")
private List<Users> users;
#ManyToOne
#JoinColumn(name = "TEAM_LEAD_ID")
private Users teamlead;
//get set...
}
I think you need to make your database fit into 3nf (third normal form). You are describing a database that uses two tables, but I think you need three at least, that way you can describe what employees are on what project. A "team" table that uses the PK's from the other two tables should be used. Conventionally, you would name it something like "ProjectEmployees" as it is comprised of the PK's from the "Projects" table and the "Employees" table respectively. I hope that answers your question. If you don't understand what I'm talking about, I highly recommend you watch this.
I have a scenerio where one staff can belong to multiple organisation and for each organisation he can have different role. How can i map this in jpa?
Staff.java
public class Staff {
#ManyToMany
#JoinTable(name="STAFF_ORGANIZATION",joinColumns=#JoinColumn(name="staff_id"),inverseJoinColumns=#JoinColumn(name="organization_id"))
private Set<Organization> organizations;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
}
Organization.java
public class Organization {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column
private String OrganizationName;
#ManyToMany(mappedBy="organizations")
private Set<Staff> staff;
}
StaffRoles.java
public class StaffRoles {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column
#Enumerated(EnumType.ORDINAL)
private Roles roles;
public enum Roles {
USER(100), ADMIN(200);
private int values;
Roles(int values) {
this.values = values;
}
public int getValues() {
return values;
}
}
Can anyone please help me in mapping the roles to the staff. So many staff can belong to many organisation and for each organisation he can have different role.
Any help will be highly appreciated!
Althought this question is not written clearly I will answer your question based on what I have understood.
Below is an ER-diagram for how your tables might look like.
Now you just need to create the classes needed.
User.java
Organization.java
UserOrganization.java
UserRole.java
Connect the right instance variables now via ManyToMany and OneToOne to achieve your goal.
EDIT:
After the question has been updated with more specific information, I can aid more in this answer. First make a StaffOrganizationRoles class that will sit between StaffOrganization and Roles. Next, make StaffOrganization sit between Staff and Organization, which means that instead of ManyToMany it will be ManyToOne from Staff -> StaffOrganization, and ManyToOne from Organization > StaffOrganization.
public class StaffOrganizationRoles {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "stafforganization_id", unique = false, nullable = false)
private StaffOrganization user;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "role_id", unique = false, nullable = false)
private Role role;
}
Staff organization class:
public class StaffOrganization {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "staff_id", unique = false, nullable = false)
private Staff staff;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "organization_id", unique = false, nullable = false)
private Organization organization;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "staffOrganization")
private Set<StaffOrganizationRoles> staffOrganizationRoles = new HashSet<>(0);
}
I've edited the picture above to represent the new ER-diagram.
Hope this will help you now.
I use hibernate and spring-data. There are two tables with many-to-many relationship.
#Entity
#Table(name = "FirstEntity")
public class FirstEntity {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "first_entity_id")
private Long id;
#Column(name = "first_entiry_name")
private String name;
/* getters and setters are below*/
}
#Entity
#Table(name = "SecondEntity")
public class SecondEntity {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "second_entity_id")
private Long id;
#Column(name = "second_entiry_name")
private String name;
#Column(name = "second_entiry_desc")
private String description;
/* getters and setters are below*/
}
And entity for cross-reference table.
#Entity
#Table(name = "FirstSecondEntity")
public class FirstSecondEntity {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "first_second_entity_id")
private Long id;
#Column(name = "first_entity_id")
private Long firstEntityId;
#Column(name = "second_entity_id")
private Long secondEntityId;
/* getters and setters are below*/
}
I need SELECT like this
SELECT FirstEntity.name, SecondEntity.name, SecondEntity.description FROM SecondEntity INNER JOIN FirstSecondEntity ON SecondEntity.id = FirstSecondEntity.secondEntityId INNER JOIN User ON FirstEntity.id = FirstSecondEntity.firstEntityId
i.e. I need all records from cross-reference table where instead of ids there is actual info from entities.
Inserting this query into #Query annotation in my CrudRepository-extended class doesn't work because of
ERROR [main][org.hibernate.hql.internal.ast.ErrorCounter] Path expected for join!
So I need your help.
Your join table is all screwed up. In this case, you actually don't even need the join table as a hibernate mapping:
In Second Entity add the following list:
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(name = "FirstSecondEntity",
joinColumns = {
#JoinColumn(name = "first_entity_id",
nullable = false,
updatable = false) },
inverseJoinColumns = {
#JoinColumn(name = "second_entity_id",
nullable = false,
updatable = false) },
)
private List<FirstEntity> firstEntities;
In FirstEntity add the following list:
#ManyToMany(fetch = FetchType.LAZY,
mappedBy = "firstEntities")
private List<SecondEntity> secondEntities;