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!
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?
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 |
I need to get values from user table, in that user have an manager id,
Manager is an user so again manager id is mapped with user entity.
This will cause continuous iteration until the manager ID get null.
\
The entity get more on inside on it > User entity > manager id> --> user entity ....
Is there any possible to get single entity with single manager using hibernate query?
USER_NAME (PK)
CREATE_DATE
UPDATED_DATE
ROLE_ID
USER_ID
MANAGER_ID
REGION_ID
USER_GROUP
Created_By
User class
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "USER_ID", unique = true, nullable = false)
private Long userId;
#ManyToOne( targetEntity = User.class, cascade = CascadeType.ALL)
#JoinColumn(name = "MANAGER_ID", referencedColumnName = "USER_ID")
private User managerId;
You can relate to entity only managerId(I mean Long type), or you can mark Many to one relation with fetch = FetchType.LAZY and call this field only if needed.