Multiple tables with QueryDSL - spring-boot

I have three tables connected together and I am trying to pull the data from three tables using queryDSL.
DROP TABLE IF EXISTS countries;
CREATE TABLE countries(id BIGINT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100), data VARCHAR(100));
DROP TABLE IF EXISTS states;
CREATE TABLE states(id BIGINT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100), count VARCHAR(100), co_id BIGINT );
DROP TABLE IF EXISTS towns;
CREATE TABLE towns(town_id BIGINT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100), people_count VARCHAR(100), st_id BIGINT);
Data
INSERT INTO countries (id, name, data) VALUES (1, 'USA', 'wwf');
INSERT INTO countries (id, name, data) VALUES (2, 'France', 'football');
INSERT INTO countries (id, name, data) VALUES (3, 'Brazil', 'rugby');
INSERT INTO countries (id, name, data) VALUES (4, 'Italy', 'pizza');
INSERT INTO countries (id, name, data) VALUES (5, 'Canada', 'snow');
INSERT INTO states (id, name, count, co_id) VALUES (1, 'arizona', '1000', 1);
INSERT INTO states (id, name, count, co_id) VALUES (2, 'texas', '400', 4);
INSERT INTO states (id, name, count, co_id) VALUES (3, 'ottwa', '3000', 1);
INSERT INTO states (id, name, count, co_id) VALUES (4, 'paulo', '222', 3);
INSERT INTO states (id, name, count, co_id) VALUES (5, 'paris', '544', 1);
INSERT INTO towns (town_id, name, people_count, st_id) VALUES (1, 'arizona', '1000', 1);
INSERT INTO towns (town_id, name, people_count, st_id) VALUES (2, 'texas', '400', 2);
INSERT INTO towns (town_id, name, people_count, st_id) VALUES (3, 'fff', '3000', 1);
INSERT INTO towns (town_id, name, people_count, st_id) VALUES (4, 'fsdd', '222', 3);
INSERT INTO towns (town_id, name, people_count, st_id) VALUES (5, 'fsfdds', '544', 3);
Entities
#Entity
#Table(name = "countries")
#Setter
#Getter
public class Country {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long countryId;
#Column(name = "name")
private String name;
#Column(name = "data")
private String data;
#OneToOne(mappedBy = "country")
private State stateJoin;
}
#Entity
#Table(name = "states")
#Setter
#Getter
public class State {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long stateId;
#Column(name = "name")
private String name;
#Column(name = "count")
private String count;
#Column(name = "co_id")
private Long countryId;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "co_id", referencedColumnName = "id", updatable = false, insertable = false)
private Country country;
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name = "state_id", referencedColumnName = "id")
private Set<Town> towns;
}
#Entity
#Table(name = "towns")
#Setter
#Getter
public class Town {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "town_id")
private Long townId;
#Column(name = "name")
private String name;
#Column(name = "people_count")
private String peopleCount;
#Column(name = "st_id")
private Long stateId;
}
I am trying to run the below QueryDSL to get the whole data from the above tables especially since I am looking for the data from the state table with a set of records of towns.
Case-1
Projection1
#Component
#Data
#AllArgsConstructor
#NoArgsConstructor
public class SecondDto {
private String name;
private State state;
}
Query
QCountry country = QCountry.country;
QState state = QState.state;
JPAQuery query = new JPAQuery(entityManager);
List<SecondDto> result1 = query
.select(Projections.constructor(SecondDto.class, country.name, country.stateJoin))
.from(country)
.join(country.stateJoin, QState.state)
.join(state.towns, QTown.town)
.fetch();
System.out.println("*** "+ result1);
Result logs and generated queries
Hibernate:
/* select
country.name,
country.stateJoin
from
Country country
inner join
country.stateJoin as state
inner join
state.towns as town */ select
country0_.name as col_0_0_,
country0_.id as col_1_0_,
state1_.id as id1_1_,
state1_.count as count2_1_,
state1_.co_id as co_id3_1_,
state1_.name as name4_1_
from
countries country0_
inner join
states state1_
on country0_.id=state1_.co_id
inner join
towns towns2_
on state1_.id=towns2_.state_id
*** [] --- No response even though I have the data in DB.
Case-2
Projecton2
#Component
#Data
#AllArgsConstructor
#NoArgsConstructor
public class Dto {
private String name;
private Set<Town> towns;
}
Query
List<Dto> result = query
.select(Projections.constructor(Dto.class, state.name, state.towns))
.from(state)
.join(state.towns, QTown.town)
.fetch();
this one creates the below logs with an exception.
/* select
state.name,
state.towns
from
State state
inner join
state.towns as town */ select
state0_.name as col_0_0_,
. as col_1_0_, <--- Here I am getting issue
towns2_.town_id as town_id1_2_,
towns2_.name as name2_2_,
towns2_.people_count as people_c3_2_,
towns2_.st_id as st_id4_2_
from
states state0_
inner join
towns towns1_
on state0_.id=towns1_.state_id
inner join
towns towns2_
on state0_.id=towns2_.state_id
07-01-2023 14:33:02 [restartedMain] WARN org.hibernate.engine.jdbc.spi.SqlExceptionHelper.logExceptions - SQL Error: 42001, SQLState: 42001
07-01-2023 14:33:02 [restartedMain] ERROR org.hibernate.engine.jdbc.spi.SqlExceptionHelper.logExceptions - Syntax error in SQL statement "/* select state.name, state.towns\000afrom State state\000a inner join state.towns as town */ select state0_.name as col_0_0_, [*]. as col_1_0_, towns2_.town_id as town_id1_2_, towns2_.name as name2_2_, towns2_.people_count as people_c3_2_, towns2_.st_id as st_id4_2_ from states state0_ inner join towns towns1_ on state0_.id=towns1_.state_id inner join towns towns2_ on state0_.id=towns2_.state_id"; expected "*, INTERSECTS (, NOT, EXISTS, UNIQUE, INTERSECTS"; SQL statement:
/* select state.name, state.towns
from State state
inner join state.towns as town */ select state0_.name as col_0_0_, . as col_1_0_, towns2_.town_id as town_id1_2_, towns2_.name as name2_2_, towns2_.people_count as people_c3_2_, towns2_.st_id as st_id4_2_ from states state0_ inner join towns towns1_ on state0_.id=towns1_.state_id inner join towns towns2_ on state0_.id=towns2_.state_id [42001-214]
07-01-2023 14:33:02 [restartedMain] INFO org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener.logMessage -
My main goal is to use case-1 and get combined data from three entities. The complete SpringBoot project can be found in here
Can anyone help me with how can I achieve this with queryDSL?

First, your model is incorrect. There can be multiple states in a country, so you should rather model the Country<->State relationship with a one-to-many association:
#Entity
#Table(name = "countries")
#Setter
#Getter
public class Country {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long countryId;
#Column(name = "name")
private String name;
#Column(name = "data")
private String data;
#OneToMany(mappedBy = "country")
private Set<State> states;
}
#Entity
#Table(name = "states")
#Setter
#Getter
public class State {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long stateId;
#Column(name = "name")
private String name;
#Column(name = "count")
private String count;
#Column(name = "co_id")
private Long countryId;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "co_id", referencedColumnName = "id", updatable = false, insertable = false)
private Country country;
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name = "state_id", referencedColumnName = "id")
private Set<Town> towns;
}
I would recommend you to look into Blaze-Persistence Entity Views for this though as that will simplify the querying.
I created the library to allow easy mapping between JPA models and custom interface or abstract class defined models, something like Spring Data Projections on steroids. The idea is that you define your target structure(domain model) the way you like and map attributes(getters) via JPQL expressions to the entity model.
A DTO model for your use case could look like the following with Blaze-Persistence Entity-Views:
#EntityView(Country.class)
public interface CountryDto {
#IdMapping
Long getId();
String getName();
Set<StateDto> getStates();
#EntityView(State.class)
interface StateDto {
#IdMapping
Long getId();
String getName();
}
}
Querying is a matter of applying the entity view to a query, the simplest being just a query by id.
CountryDto a = entityViewManager.find(entityManager, CountryDto.class, id);
The Spring Data integration allows you to use it almost like Spring Data Projections: https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features
Page<CountryDto> findAll(Pageable pageable);
The best part is, it will only fetch the state that is actually necessary!

Related

Is that possible in spring boot that join column (foreign key) with id

I want to join column without object reference. is that possible?
I want to do foreign key without object reference like that
#Data
#Entity
#Table(name = "HRM_EMPLOYEE_SALARY_INCREMENT")
public class EmployeeSalaryIncrement implements Serializable {
private static final long serialVersionUID = 9132875688068247271L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="ID")
private Integer id;
#Column(name = "REFERENCE_NO")
private String referenceNo;
#ManyToOne
#JoinColumn(name = "AUTHORITY", referencedColumnName = "id")
private Integer authority;
#ManyToOne
#JoinColumn(name = "PART_TWO_REGISTER_ID")
private Integer partTwoRegisterId;
#Column(name = "PART_TWO_ORDER_NO")
private String partTwoOrderNo;
#Column(name = "REMARKS")
private String remarks;
#Column(name = "HRM_TYPE")
private Integer hrmType;
}
If I found solve this problem, it will helpful for me.
Joining is not needed in this case. If you only need the foreign key value, then simply add the column as a #Column like any other:
#Data
#Entity
#Table(name = "HRM_EMPLOYEE_SALARY_INCREMENT")
public class EmployeeSalaryIncrement implements Serializable {
private static final long serialVersionUID = 9132875688068247271L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="ID")
private Integer id;
#Column(name = "AUTHORITY")
private Integer authority;
// other fields
// ...
}
No, I don't think that you can join columns between two entities without adding the reference of one to the related entity. You will have to create one entity class corresponding to each of your relational database table and add the reference of one to the other to establish relation.
However, I understand that you may not need all the attributes from your related table based upon your use case, and only wish to select one column from it. You can do that either by only adding required attributes in your joined table entity class (if you are sure you won't need other attributes for that table anywhere else).
Or you can use custom queries using JPQL in your repository class which selects only the required attributes from the tables that you have joined.
I will show you an example of the second way:
//Say, this is your entity class where you wish to join other table to fetch only one attribute from the joined table-
#Entity
#Table(name = "TABLE1", schema = "SCHEMA1")
public class Table1 {
#Id
#Column(name = "ID")
private String id;
#Column(name = "TABLE2_COLUMN")
private String table2Column;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "TABLE2_COLUMN1")
private Table2 table2; //refrence of the joined table entity object
}
// And this is the joined table entity class
#Entity
#Table(name = "TABLE2", schema = "SCHEMA1")
public class Table2 {
#Id
#Column(name = "ID")
private String id;
#Column(name = "TABLE2_COLUMN1")
private String table2Column1;
#Column(name = "TABLE2_COLUMN2")
private String table2Column2; // The column which we want to select from the joined table
}
In your repository class -
#Repository
public interface Table1Repository extends JpaRepository<Table1, String> {
#Query("SELECT t1 FROM Table1 t1 WHERE t1.id = :id")
public List<Table1> getTable1Rows(#Param("id") String id);
#Query("SELECT t1.table2.table2Column2 FROM Table1 t1 WHERE t1.id = :id")
public String getTable2Column2(#Param("id") String id);
}
Based upon the response from Markus Pscheidt below, I agree when he said there's no need to join the entities if you only need the attribute which is a foreign key. As foreign key is already present as an attribute in your entity (or table) you are working with.
If you need to fetch any other column apart from foreign key, then you may use JPQL to fetch the exact column that you wish to select.

Why OneToMany JPA association is failing while insert statement executes

Hi below is my schema definition
CREATE TABLE LOANS (
LOAN_ID NUMBER(9,0) PRIMARY KEY,
CORR_ID VARCHAR(5) NULL
);
CREATE TABLE DV_LOAN_PARTICIPANTS (
LOAN_ID NUMBER(9,0) ,
DVP_PARTICIPANT_NAME VARCHAR(50) NOT NULL,
DVP_PARTICIPANT_TYPE VARCHAR(50) NOT NULL,
PRIMARY KEY ("LOAN_ID", "DVP_PARTICIPANT_NAME")
);
LOANS Entity
#Table(name = "LOANS")
#Entity
public class Loans {
#Id
#Column(name = "LOAN_ID")
private Long loanId;
#OneToMany(cascade = CascadeType.ALL,fetch = FetchType.EAGER)
#JoinColumn(name = "LOAN_ID")
#MapKey(name = "dvpParticipantName")
private Map<String, DVLoanParticipants> dvLoanParticipantsMap;
// getter and setters
}
DV_LOAN_PARTICIPANTS Entity
#Table(name = "DV_LOAN_PARTICIPANTS")
#Entity
public class DVLoanParticipants implements Serializable {
#Id
#Column(name = "LOAN_ID")
private Long loanId;
#Id
#Column(name = "DVP_PARTICIPANT_NAME")
private String dvpParticipantName;
#Column(name = "DVP_PARTICIPANT_TYPE")
private String dvpParticipantType;
// getters and setters
}
Service Class is
DVLoanParticipants dvLoanParticipants = new DVLoanParticipants();
dvLoanParticipants.setLoanId(Long.valueOf("196801758"));
dvLoanParticipants.setDvpParticipantName("VKP");
dvLoanParticipants.setDvpParticipantType("Developer");
Loans loanInsert = new Loans();
loanInsert.setLoanId(Long.valueOf("196801758"));
Map<String,DVLoanParticipants> partyMap = new HashMap<>();
partyMap.put("VKP",dvLoanParticipants);
loanInsert.setDvLoanParticipantsMap(partyMap);
repository.save(loanInsert);
But when i am executing the save i am getting error as
NULL not allowed for column "LOAN_ID"; SQL statement:
insert into dv_loan_participants (dvp_participant_type, loan_id, dvp_participant_name) values (?, ?,
?)
Git Hub Code
https://github.com/vinoykp/spring-jpa/tree/master/spring-boot-hibernate-crud-demo
I had the similar question
Why Value is not getting assigned in JPA for insert statement
What is the issue in association?

ManyToMany relationship removes all entities

I have two entities, user and movies. They're manytomany bidirectional relationship. My problem is that when I delete a movie via my controller it also removes all related with that movie entities. My user and this user roles and the movie entity. What have I to do, to get rid just off movie entity from the table when delete it and keep the user with his roles instead of removing them all.
#Data
#ToString
#EqualsAndHashCode
#Entity
#Table(name = "movies")
public class Movie {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "title")
private String title;
#Column(name = "description")
private String description;
#Column(name = "release_date")
#Temporal(TemporalType.DATE)
private Date release_date;
#Column(name = "country")
private String country;
#Column(name = "category")
private String category;
#ManyToMany(mappedBy = "movies")
#ToString.Exclude
#EqualsAndHashCode.Exclude
private Set<User> users = new HashSet<>();
#Data
#ToString
#Entity
#Table(name = "users")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "username")
private String username;
#Column(name = "password")
private String password;
#Transient
private String confirmPassword;
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(name = "users_roles", joinColumns = {#JoinColumn(name = "user_id", referencedColumnName = "id")},
inverseJoinColumns = {#JoinColumn(name = "role_id", referencedColumnName = "id")})
#ToString.Exclude
#EqualsAndHashCode.Exclude
private Set<Role> roles = new HashSet<>();
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(name = "users_movies", joinColumns = {#JoinColumn(name = "user_id", referencedColumnName = "id")},
inverseJoinColumns = {#JoinColumn(name = "movie_id", referencedColumnName = "id")})
#ToString.Exclude
#EqualsAndHashCode.Exclude
private Set<Movie> movies = new HashSet<>();
this is the expected behavior when you use CascadeType.ALL, which implicitly includes CascadeType.REMOVE - that removes all the related entities on removing the owning entity.
Since you are using CascadeType.ALL on both sides of the association, as a result you end up deleting records more than what you actually intended.
To avoid this:
You need to remove the CascadeType.ALL or change it to something appropriate like MERGE / PERSIST
Handle the deletion of entities on your own.
Consider using batch delete option specifying the associated entity id.
Problem solved, instead of using mappedBy I added a JoinTable annotation also to Movie entity and now it works as it should.
Well, I had to guess what your Role entity looks like so include complete examples. You didn't specify whether you were using Spring-Data-Jpa or just Jpa so who knows. Edit: in your examples you have finally clarified that you are using spring-data-jpa, but the concepts are the same as here anyway.
#Data
#ToString
#Entity
#Table(name = "roles")
public class Role {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToMany(mappedBy="roles")
#ToString.Exclude
#EqualsAndHashCode.Exclude
private Set<User> users = new HashSet<>();
}
and to use
tx.begin();
User u1 = new User();
Role r1 = new Role();
u1.setRoles(Collections.singleton(r1));
Movie m1 = new Movie();
m1.setDescription("movie 1");
Movie m2 = new Movie();
m2.setDescription("movie 2");
u1.setMovies(Stream.of(m1, m2).collect(Collectors.toSet()));
em.persist(u1);
tx.commit();
// now to query
em.clear();
tx.begin();
User u = em.createQuery("from User u left outer join fetch u.movies where u.id = 1", User.class).getSingleResult();
Movie m = u.getMovies().stream().filter(mv->mv.getDescription().equals("movie 1")).findFirst().get();
u.getMovies().remove(m);
em.remove(m);
tx.commit();
and this creates the log
create table users (id bigint generated by default as identity (start with 1), password varchar(255), username varchar(255), primary key (id))
create table users_movies (user_id bigint not null, movie_id bigint not null, primary key (user_id, movie_id))
create table users_roles (user_id bigint not null, role_id bigint not null, primary key (user_id, role_id))
alter table users_movies add constraint FKt4hasm7tvj0vor58ql33xptjy foreign key (movie_id) references movies
alter table users_movies add constraint FKhhj9vi206o88q0typfntk3fek foreign key (user_id) references users
alter table users_roles add constraint FKj6m8fwv7oqv74fcehir1a9ffy foreign key (role_id) references roles
alter table users_roles add constraint FK2o0jvgh89lemvvo17cbqvdxaa foreign key (user_id) references users
insert into users (id, password, username) values (default, ?, ?)
insert into movies (id, category, country, description, release_date, title) values (default, ?, ?, ?, ?, ?)
insert into movies (id, category, country, description, release_date, title) values (default, ?, ?, ?, ?, ?)
insert into roles (id) values (default)
insert into users_movies (user_id, movie_id) values (?, ?)
insert into users_movies (user_id, movie_id) values (?, ?)
insert into users_roles (user_id, role_id) values (?, ?)
select user0_.id as id1_2_0_, movie2_.id as id1_0_1_, user0_.password as password2_2_0_, user0_.username as username3_2_0_, movie2_.category as category2_0_1_, movie2_.country as country3_0_1_, movie2_.description as descript4_0_1_, movie2_.release_date as release_5_0_1_, movie2_.title as title6_0_1_, movies1_.user_id as user_id1_3_0__, movies1_.movie_id as movie_id2_3_0__ from users user0_ left outer join users_movies movies1_ on user0_.id=movies1_.user_id left outer join movies movie2_ on movies1_.movie_id=movie2_.id where user0_.id=1
delete from users_movies where user_id=? and movie_id=?
delete from movies where id=?

creating relationship table at startup MySQL Spring Boot from data.sql

Hello i have a task to build an application using spring boot and hibernate. The thing is i'm building the database through a data.sql file to persist data and create the database. Now i need to create a relationship table between my two tables. This should be a one to many relationship given that a worker can have a user account or may not have an account. The problem lies on how to build this relationship table when the application starts because the references should be the foreign keys user_id and worker_id which i do not have at startup because they are created automatically by hibernate so there's no way to hardcode them. So the question is how would i go about creating this relationchip table from data.sql.
data.sql:
INSERT INTO worker (name, last_name, status) VALUES
('manuel', 'dias', 'active'),
('sailin ', 'nal', 'active'),
('abraham', 'lincon', 'active'),
('mick', 'smith', 'active'),
('jose', 'perez', 'inactive'),
('luis', 'nuñez', 'inactive'),
('ruben', 'puertas', 'inactive'),
('anders', 'stone', 'inactive'),
('luis', 'alvarez', 'deleted'),
('claudio', 'martinez', 'deleted'),
('morfeo', 'rodriguez', 'active'),
('onetys', 'estrada', 'inactive'),
('rene', 'fajardo', 'active');
INSERT INTO users (username, password, user_type, status) VALUES
('madi', 'madi', 'worker', 'active'),
('sana', 'sana', 'worker', 'active'),
('abli', 'abli', 'worker', 'active'),
('mism', 'mism', 'worker', 'active'),
('jope', 'jope', 'worker', 'active'),
('lunu', 'lunu', 'worker', 'active'),
('rupu', 'rupu', 'worker', 'active'),
('anst', 'anst', 'worker', 'active'),
('lual', 'lual', 'worker', 'active'),
('clma', 'clma', 'worker', 'active');
Users.class:
#Entity
#Table(name = "users")
public class Users implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "user_id", nullable = false)
private int userId;
#Column(name = "username")
private String username;
#Column(name = "password")
private String password;
#Column(name = "userType")
private String userType;
#Column(name = "status")
private String status;
#ManyToOne
#JoinColumn(name = "worker_id")
private Worker worker;
Worker.class:
#Entity
#Table(name = "worker")
public class Worker implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "worker_id")
private int workerId;
#Column(name = "name")
private String name;
#Column(name = "last_name")
private String lastName;
#Column(name = "status")
private String status;
#OneToMany(mappedBy = "worker", cascade = CascadeType.ALL)
private Collection<Users> users;
So do i have to:
1: Create another Entity to be able to make a new table in the database holding the foreign keys to user and worker entities?
2: Can it be done with a script in data.sql.
I would create a column in users table referencing the worker id but the task explicitly says:
"make a third table to hold the relationship"
Thanks in advance
In OneToMany relationship, you can have all needed information on the entity of the many side. Creating another join table only makes sense on ManyToMany relationship, it would only add redundant data on OneToMany and violates normalization.
That being said, if you really need another table to define the two entities relationship, you can achieve this without creating another entity using #JoinTable.
#Entity
#Table(name = "users")
public class Users implements Serializable {
//....
#ManyToOne
#JoinTable(name = "worker_users",
joinColumns = #JoinColumn(name = "user_id"),
inverseJoinColumns = #JoinColumn(name = "worker_id"))
private Worker worker;
}
#Entity
#Table(name = "worker")
public class Worker implements Serializable {
//...
#OneToMany(cascade = CascadeType.ALL) //remove mappedBy
#JoinTable(name = "worker_users",
joinColumns = #JoinColumn(name = "worker_id"),
inverseJoinColumns = #JoinColumn(name = "user_id"))
private Collection<Users> users;
}
It would create new worker_user table with this structure
|WORKER_ID |USER_ID |

Spring data JPA join table with extra column

I'm trying to implement a meeting model which contains multiple equipment entity with corresponding quantity.
In the view of meeting, user should be able to CRUD equipment and quantity of this equipment of a meeting
databases:
CREATE TABLE IF NOT EXISTS equipment (
equipment_id SERIAL PRIMARY KEY,
equipment_name VARCHAR(20) NOT NULL
);
CREATE TABLE IF NOT EXISTS meeting (
meeting_id SERIAL PRIMARY KEY,
meeting_time TIMESTAMP NOT NULL,
number_people INTEGER NOT NULL,
setup VARCHAR(255)
);
CREATE TABLE IF NOT EXISTS meeting_equipment (
meeting_equipment_id SERIAL PRIMARY KEY ,
meeting_id INTEGER NOT NULL REFERENCES meeting (meeting_id),
equipment_id INTEGER NOT NULL REFERENCES equipment (equipment_id),
quantity INTEGER NOT NULL DEFAULT 0
);
Entity implementation:
#Entity
#Table(name = "meeting")
#Data
public class Meeting {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "meeting_id", updatable = false)
#JsonIgnore
private int id;
#Column(name = "meeting_time")
#JsonFormat(pattern = "yyyy-MM-dd HH:mm")
#NotNull
private LocalDateTime meetingTime;
#Column(name = "number_people")
#NotNull
#Min(1)
private int numberPeople;
#Column(name = "setup")
#NotNull
private String setup;
#OneToMany(mappedBy = "meeting", cascade = CascadeType.ALL)
#JsonManagedReference
List<MeetingEquipment> equipmentList = new ArrayList<>();
}
#Entity
#Table(name = "equipment")
#Data
public class Equipment {
#Id
#Column(name = "equipment_id", updatable = false)
#JsonIgnore
private int id;
#NotNull
#Column(name = "equipment_name", unique = true)
#Size(min = 1, max = 100)
private String equipmentName;
}
Join table metting_equipment:
#Entity
#Table(name = "meeting_equipment", uniqueConstraints = {
#UniqueConstraint(columnNames = {"meeting_id", "equipment_id"})})
#Data
public class MeetingEquipment {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "meeting_equipment_id", updatable = false)
#JsonIgnore
private int id;
#ManyToOne
#JoinColumn(name = "meeting_id")
#NotNull
#JsonBackReference
private Meeting meeting;
#ManyToOne
#JoinColumn(name = "equipment_id")
#NotNull
private Equipment equipment;
#Column(name = "quantity")
#NotNull
private int quantity;
}
Using the code above, I can successfully create meeting with equipment included (JSON returned from creation method shows correct content). But once I try to remove an element of equipmentList in meeting entity, it does not delete meetingEquipment entity. I tried
meeting.getEquipmentList().clear() and meetingEquipmentDao.delete(meeting.getEquipmentList()), neither works.
Could anyone tell me the cause of this problem, thanks!

Resources