I have a products table that contains especially a product_name and a product_type.
For certain product types, I'd like to create some kind of overlay mapping table that replaces the value in product_name.
In pure mysql, I would solve this as follows:
CREATE TABLE products (
id int NOT NULL AUTO_INCREMENT,
product_type varchar(20) NOT NULL,
product_name varchar(255) NOT NULL,
product_price;
product_quantity;
...
)
#Entity
public class Product {
long id;
String product_type;
String product_name;
String product_price;
...
}
CREATE TABLE product_mapping (
id int NOT NULL AUTO_INCREMENT,
product_type varchar(20) NOT NULL,
product_name varchar(255) NOT NULL,
PRIMARY KEY (id)
);
My goal: if product_mapping contains the product_type, override the product_name. Else, stick to the value in products.product_name table.
SELECT ..., ifnull(product_mapping.product_name, products.product_name) AS product_name
FROM products
LEFT JOIN product_mapping ON products.product_type = product_mapping.product_type;
But how could I create the same mapping with a hibernate #Entity
Sidenote: A #Formula creates an additional SELECT for each query, whose result is merged into the #Entity. I'm looking for a JOIN!
Related
I'm new to Java Springboot and I want to join multiple tables.
I have this MySQL schema :
CREATE TABLE `users`
(
`id` int NOT NULL AUTO_INCREMENT,
`email` varchar(128) NOT NULL,
`nickname` varchar(128) NOT NULL,
`password` varchar(256) NOT NULL,CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `email` (`email`),
UNIQUE KEY `nickname` (`nickname`)
);
CREATE TABLE `organizations` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(128) NOT NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE `org_abilities`
(
`id` int NOT NULL AUTO_INCREMENT,
`key` varchar(128) NOT NULL,
`description` varchar(128) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `idx_key` (`key`) USING BTREE
);
CREATE TABLE `org_permissions`
(
`id` int NOT NULL AUTO_INCREMENT,
`id_user` int NOT NULL,
`id_organization` int NOT NULL,
`id_ability` int NOT NULL,
PRIMARY KEY (`id`),
KEY `id_organization` (`id_organization`),
KEY `id_user` (`id_user`),
KEY `users_permissions_ibfk_2` (`id_ability`),
CONSTRAINT `org_permissions_ibfk_0` FOREIGN KEY (`id_organization`) REFERENCES `organizations` (`id`),
CONSTRAINT `org_permissions_ibfk_1` FOREIGN KEY (`id_user`) REFERENCES `users` (`id`),
CONSTRAINT `org_permissions_ibfk_2` FOREIGN KEY (`id_ability`) REFERENCES `org_abilities` (`id`)
);
Where my table org_permissions represent all abilities that a user has within an organization.
I have created the corresponding Java classes. I have a JPA to fetch the datas from the DB to the classes.
I want in my Organization class to have a field Map<long, List<Pair<long, String>>> managers which map an id_user to a list of tuple of abilities where the tuple is (id_ability, org_ability.key).
Finally I use DTO to send my response, and I want my response to look like that :
{
id : _id_organization,
name : "organisation name",
managers : {
id_user: [(id_ability, key), (id_ability, key)],
id_user:[(id_ability, key), (id_ability, key)]
}
}
For example:
SELECT op.*, oa.* FROM org_permissions as op
JOIN org_abilities oa on oa.id = op.id_ability
JOIN organizations o on o.id = op.id_organization
JOIN users u on u.id = op.id_user;
Here, user with id 1 is member of organization 1 and 2. for organization 1 user 1 has the CREATE_EVENTS and DELETE_EVENTS abilities and for organization 2 he only have the DELETE_EVENTS ability.
When getting all the organization I want this result :
[{
id : 1,
name : "Org1",
managers : {
1: [(1, "CREATE_EVENT"), (2,"CREATE_EVENT")]
}
},
{
id : 2,
name : "Org2",
managers : {
1: [(2,"CREATE_EVENT")]
}
}]
Thanks for your help, I'm a bit lost with the High level of springboot and JPA
P.S.: I tried to ask to chat GPT but nothing was concluent
this is my first question here so, please ask if you need more information. I am working on a personal project. I have a relatively complex relational database structure. I create schema.sql on my spring boot project as well as data.sql with sample data. I try to create a web application for simulated fitness centre web pages. I try to display the location name and number of visits for the user. I create a userLocation bean for keeping the result set as a list of the select query. I can test the statement on H2 database and its work. However, on my code, I cannot get the number of visits from the select statement.
Here is my userlocation bean,
#Data
#NoArgsConstructor
public class UserLocation {
private String locName;
private int numOfVisit;
}
Controller class getMapping method
#GetMapping("/secure/userLocation")
public String myLocation(Model model, Authentication authentication) {
String email = authentication.getName();
User currentUser = da.findUserAccount(email);
model.addAttribute("myLocationList", da.getUserLocationList(currentUser.getUserId()));
return "/secure/userLocation";
}
Here database access method;
public List<UserLocation> getUserLocationList(Long userId) {
MapSqlParameterSource namedParameters = new MapSqlParameterSource();
String query = "SELECT l.locName, COUNT(ul.dayOfVisit) FROM location l "
+ "INNER JOIN userLocation ul ON l.locId = ul.locId "
+ "INNER JOIN sec_user sc ON ul.userId = sc.userId "
+ "WHERE sc.userId = :userId AND ul.locId = 1"
+ "GROUP BY l.locName";
namedParameters.addValue("userId", userId);
return jdbc.query(query, namedParameters, new BeanPropertyRowMapper<UserLocation>(UserLocation.class));
}
here schema.sql
CREATE TABLE location (
locId BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT,
locName VARCHAR(75),
locAddress VARCHAR(255),
locPhone VARCHAR(25),
locEmail VARCHAR(75)
);
CREATE TABLE sec_user (
userId BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(75),
lastName VARCHAR(75),
adress VARCHAR(255),
phone VARCHAR(10),
email VARCHAR(75) NOT NULL UNIQUE,
encryptedPassword VARCHAR(128) NOT NULL,
enabled BIT NOT NULL
);
CREATE TABLE coach (
coachId BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT,
coachName VARCHAR(75),
coachLevel BIGINT,
coachRating BIGINT,
aboutMe VARCHAR(255)
);
CREATE TABLE fitnessClass (
classId BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT,
className VARCHAR(75),
classPrice DOUBLE
);
CREATE TABLE generalCert (
certId BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT,
certName VARCHAR(75)
);
CREATE TABLE certCoach (
certId BIGINT NOT NULL,
coachId BIGINT NOT NULL
);
ALTER TABLE certCoach
ADD CONSTRAINT certCoach_FK1 FOREIGN KEY (certId)
REFERENCES generalCert (certId);
ALTER TABLE certCoach
ADD CONSTRAINT certCoach_FK2 FOREIGN KEY (coachId)
REFERENCES coach (coachId);
CREATE TABLE userLocation (
userLocId BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT,
locId BIGINT NOT NULL,
userId BIGINT NOT NULL,
isHomeLoc BIT,
dayOfVisit DATE
);
ALTER TABLE userLocation
ADD CONSTRAINT userLocation_FK1 FOREIGN KEY (locId)
REFERENCES location (locId);
ALTER TABLE userLocation
ADD CONSTRAINT userLocation_FK2 FOREIGN KEY (userId)
REFERENCES sec_user (userId);
CREATE TABLE amenity (
amenityId BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT,
amenityName VARCHAR(75),
locId BIGINT
);
ALTER TABLE amenity
ADD CONSTRAINT amenity_FK FOREIGN KEY (locId)
REFERENCES location (locId);
CREATE TABLE room (
roomId BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT,
roomName VARCHAR(75),
locId BIGINT
);
ALTER TABLE room
ADD CONSTRAINT room_FK FOREIGN KEY (locId)
REFERENCES location (locId);
CREATE TABLE classCoach (
classId BIGINT NOT NULL,
coachId BIGINT NOT NULL
);
ALTER TABLE classCoach
ADD CONSTRAINT classCoachFK1 FOREIGN KEY (classId)
REFERENCES fitnessClass(classId);
ALTER TABLE classCoach
ADD CONSTRAINT classCoachFK2 FOREIGN KEY (coachId)
REFERENCES coach(coachId);
CREATE TABLE schedule (
ScheduleId BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT,
ScheduleDate DATE,
ScheduleTime TIME,
RoomId BIGINT,
ClassId BIGINT NOT NULL,
LocId BIGINT NOT NULL
);
ALTER TABLE schedule
ADD CONSTRAINT scheduleFK1 FOREIGN KEY (roomId)
REFERENCES room(RoomId);
ALTER TABLE schedule
ADD CONSTRAINT scheduleFK2 FOREIGN KEY (classId)
REFERENCES fitnessClass(classId);
ALTER TABLE schedule
ADD CONSTRAINT ScheduleFK3 FOREIGN KEY (LocId)
REFERENCES location(LocId);
CREATE TABLE reservation (
ClassId BIGINT NOT NULL,
userId BIGINT NOT NULL
);
ALTER TABLE reservation
ADD CONSTRAINT reservationFK1 FOREIGN KEY (classId)
REFERENCES fitnessClass(classId);
ALTER TABLE reservation
ADD CONSTRAINT reservationFK2 FOREIGN KEY (userId)
REFERENCES sec_user(userId);
CREATE TABLE workFrom (
coachId BIGINT NOT NULL,
locId BIGINT NOT NULL
);
ALTER TABLE workFrom
ADD CONSTRAINT workFromFK1 FOREIGN KEY (coachId)
REFERENCES coach(coachId);
ALTER TABLE workFrom
ADD CONSTRAINT workFromFK2 FOREIGN KEY (locId)
REFERENCES location(locId);
CREATE TABLE review (
ReviewId BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT,
CoachId BIGINT NOT NULL,
userId BIGINT NOT NULL,
ReviewDate DATE,
ComScore CHAR(1),
EnthScore CHAR(1),
PunctScore CHAR(1),
ReviewText VARCHAR(500)
);
ALTER TABLE review
ADD CONSTRAINT reviewFK1 FOREIGN KEY (coachId)
REFERENCES coach(coachId);
ALTER TABLE review
ADD CONSTRAINT reviewFK2 FOREIGN KEY (userId)
REFERENCES sec_user(userId);
CREATE TABLE Reference (
CoachId BIGINT NOT NULL,
userId BIGINT NOT NULL
);
ALTER TABLE Reference
ADD CONSTRAINT ReferenceFK1 FOREIGN KEY (coachId)
REFERENCES coach(coachId);
ALTER TABLE review
ADD CONSTRAINT ReferenceFK2 FOREIGN KEY (userId)
REFERENCES sec_user(userId);
CREATE TABLE ClientCoach (
coachId BIGINT NOT NULL,
userId BIGINT NOT NULL,
myCoach BIT
);
ALTER TABLE ClientCoach
ADD CONSTRAINT ClientCoachFK1 FOREIGN KEY (coachId)
REFERENCES coach(coachId);
ALTER TABLE ClientCoach
ADD CONSTRAINT ClientCoachFK2 FOREIGN KEY (userId)
REFERENCES sec_user(userId);
CREATE TABLE sec_role(
roleId BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT,
roleName VARCHAR(30) NOT NULL UNIQUE
);
CREATE TABLE user_role
(
id BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT,
userId BIGINT NOT NULL,
roleId BIGINT NOT NULL
);
ALTER TABLE user_role
ADD CONSTRAINT user_role_uk UNIQUE (userId, roleId);
ALTER TABLE user_role
ADD CONSTRAINT user_role_fk1 FOREIGN KEY (userId)
REFERENCES sec_user (userId);
ALTER TABLE user_role
ADD CONSTRAINT user_role_fk2 FOREIGN KEY (roleId)
REFERENCES sec_role (roleId);
Here the result web page
Here is EERD for the schema
Please try:
SELECT l.locName, COUNT(ul.dayOfVisit) AS numOfVisit -- ...
(to alias numOfVisit), since we are using a BeanPropertyRowMapper (which mapps by "bean properties" (i.e. "field names"): https://www.google.com/search?q=java+bean+naming+conventions).
Alternatively use an other/custom RowMapper.
And since even javadoc recommends:
... For best performance, consider using a custom RowMapper implementation.
Best:
return jdbc.query(query, namedParameters,
(ResultSet rs, int rowNum) -> { // one ResultSet per row:
// column indices start with 1(!):
return new UserLocation(rs.getString(1), rs.getInt(2));
// alternatively (name based): rs.getString("locName")...
}
);
;)
RowMapper javadoc (spring-jdbc:current)
ResultSet javadoc (jdk17)
and since RowMapper is a/meets the requirements of a functional interface, we can write it as lambda expression.
Update 2
Query:
select distinct p.name, u.cookie_id
from product p
left join user_product up on p.id = up.product_id
left join user u on up.user_id = u.id
where p.active = true
and
(
u.cookie_id = '4c2fe5b2-73fe-4b28-baa6-23db0512114c'
or
not (exists (
select p1.id
from user_product up1, product p1
where p1.id = up1.product_id
))
)
Output:
how should be:
Update 1
I wrote the code with the use of stream() for the better understanding of the problem:
List<Product> productList = productRepository.findAllByActiveTrue();
productList = productList.stream().map(item -> {
if(item.getUserProducts() == null) return item;
List<UserProduct> userProductList = new ArrayList<>();
for (UserProduct userProduct : item.getUserProducts()) {
if(userProduct.getUser().getCookieId().equals(cookieId)){
userProductList.add(userProduct);
}
}
item.setUserProducts(userProductList);
return item;
}).collect(Collectors.toList());
I would like to know how correctly select data from the tables. I want to get all products.
But to get all products is easy. I also need to include in the output data (UserProducts and User) if there's a connection between Product and User by CookieId. In other words, I want to show all products with User and UserProducts (if possible) and exclude the relation Product-UserProduct-User if User's cookieId doesn't match the cookieId from the query.
I am trying the following query, but it returns me only products that has the connection between User and the product, not all products.
#Query("from Product pr join fetch pr.userProducts up left join fetch up.user u where pr.active = true and u.cookieId = :cookieId")
List<Product> getAllProductsByCookieId(UUID cookieId);
My database looks like this:
Visualisation of the idea:
SQL-queries to generate tables:
product-table
create table if not exists product
(
id bigint auto_increment
primary key,
active bit not null,
image_path varchar(255) null,
name varchar(255) null,
price double not null,
unit_number double null,
unit_type varchar(255) null
);
userProduct-table
create table if not exists user_product
(
quantity int null,
product_id bigint not null,
user_id bigint not null,
primary key (product_id, user_id),
constraint FKnw43wab2rt35jmofmpbhkibco
foreign key (product_id) references product (id),
constraint FKq5o2e33vlwpfc2k1mredtia6p
foreign key (user_id) references user (id)
);
user-table
create table if not exists user
(
id bigint auto_increment
primary key,
cookie_id varchar(255) null
);
Your requirement is not possible without scaler objects in JPA. i.e JPA cannot give you a Product object where p.getUserProducts() contains only some UserProducts.
See my answer here. Why left join on CriteriaQuery doesn't filter results?
or here problems with OneToMany including a filter clause in spring jpa
You have to use the native query option or any other option where you retrieve the columns and provide a mapper as to how to create the object. You can use the following sql query.
select p.product, u.cookie_id
from product p
left join user_product up on p.id = up.product_id
left join user u on up.user_id = u.id and u.cookie_id = '?1'
where p.active = true
group by p.product, u.cookie_id
I have a table with columns as rows.
Now I want to apply restriction on multiple rows with "and" condition.how can we do this using hibernate criteria?
Example: Employee table
Pk ColumnName. Value
------------------------
1. Empid. 10
1 EmpName. Sachin
1. Empsalary. 10,000
2 Empid. 20
2 EmpName. Dhoni
2. Empsalary. 8000
Now I want to fetch pk's which have EmpName as sachin and empsal as 10,000
So it should return pk as 1.
Please check image attached
You can fetch the primary key list of data from DB using criteria query. Follow the below code snippet:
EntityManager enm = sessFact.createEntityManager();
CriteriaBuilder en = sessFact.getCriteriaBuilder();
CriteriaQuery<Integer> qu = en.createQuery(Integer.class);
Root<Employee> ro = qu.from(Employee.class);
qu.select(ro.get("id"));
qu.where(en.like(ro.get("empName"), "Sachin%"), en.equal(ro.get("empSalary"), 10000 ));
List<Integer> list= enm.createQuery(qu).getResultList();
for (Integer name : list) {
System.out.println("PK: " + name);
}
in the where clause you can remove the "%" and give the exact search e.g., qu.where(en.like(ro.get("empName"), "Sachin"), en.equal(ro.get("empSalary"), 10000 ));
The equivalent SQL log generated by hibernate is in below:
Hibernate: select employee0_.id as col_0_0_ from employee employee0_ where (employee0_.emp_name like ?) and employee0_.emp_salary=10000
FYI, The referred DB Table structure is as in below:
CREATE TABLE employee (
id int(11) NOT NULL AUTO_INCREMENT,
emp_name varchar(100) DEFAULT NULL,
emp_address varchar(500) DEFAULT NULL,
emp_mobile_nos varchar(100) DEFAULT NULL,
emp_salary int(12) DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
Please find the complete code related to Hibernate in GIT here - https://github.com/ctmithun/HibernateExample/blob/master/Hibernate5Annotation/src/net/roseindia/GetAllData.java
I have two tables as follows:
table1:
CREATE TABLE `Product` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`typename` varchar(255) DEFAULT NULL,
`typecode` varchar(55) DEFAULT NULL,
) ENGINE=InnoDB AUTO_INCREMENT=396 DEFAULT CHARSET=latin1;
table2:
CREATE TABLE measurements (
id int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
age_group varchar(20) NOT NULL,
articleType NOT NULL,
dimension text ,
createdOn int(11) NOT NULL,
updatedOn int(11) NOT NULL,
createdBy text NOT NULL,
)ENGINE=InnoDB AUTO_INCREMENT=396 DEFAULT CHARSET=latin1;
Now how can I join the two tables with join column measurements.articleType = product.typename in Java Persistence.
I know the concept of using one to many and many to one using foreign key(http://en.wikibooks.org/wiki/Java_Persistence/OneToMany). But the above tables does not have foreign key.
I'm here assuming you want a Many-to-Many.
In java, if you want it to be bidirectional, use a
#ManyToMany(mappedBy = "products")
public List<Product> getProducts() { ... }
and in Product
#ManyToMany
#JoinTable(name = "product_measurement")
public List<Measurement> getMeasurement() { ... }
In sql it will be :
CREATE TABLE product_measurement
(
product_measurement_id int(11) NOT NULL,
measurement_product_id int(11) NOT NULL,
FOREIGN KEY (measurement_product_id) REFERENCES measurement (id),
FOREIGN KEY (product_measurement) REFERENCES product (id)
);
You could use JPQL or HQL Native SQL to achieve that. To use Query or Named Query you need to associate the entities together.
Since it is not possible in your case, the Native SQL is the only option.
But consider creating constraints between tables to preserve the data integrity.