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.
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
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!
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.
I have 3 tables - Rasskazi (main table), CatsRelations (relations between table Rasskazi and table CatsNames) and CatsNames.
CREATE TABLE `rasskazi` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`rasskazName` varchar(777) DEFAULT NULL,
`rasskazText` text,
`rasskazDataDobav` datetime DEFAULT NULL,
`rasskazRazmer` float DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8;
CREATE TABLE `catsRelations` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`rasskazId` int(11) DEFAULT NULL,
`catId` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `rasskazIdFK_idx` (`rasskazId`),
KEY `catIdFK_idx` (`catId`),
CONSTRAINT `z1` FOREIGN KEY (`rasskazId`) REFERENCES `rasskazi` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `z2` FOREIGN KEY (`catId`) REFERENCES `catsNames` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `catsNames` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`catName` varchar(777) DEFAULT NULL,
`oldId` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `oldId_UNIQUE` (`oldId`)
) ENGINE=InnoDB AUTO_INCREMENT=39 DEFAULT CHARSET=utf8;
Hibernate objects are:
Rasskazi.hbm.xml [http://pastebin.com/CF4D47M1][1]
Rasskazi.java [http://pastebin.com/29phnEEd][2]
CatsRelations.hbm.xml [http://pastebin.com/MqnXuAQ9][3]
CatsRelations.java [http://pastebin.com/BDqTKqeD][4]
CatsNames.hbm.xml [http://pastebin.com/9YtVkCjD][5]
CatsNames.java [http://pastebin.com/uwpWcLha][6]
All files packed to the zip and can be download here
I try to save objects by code
Rasskazi r = new Rasskazi();
r.setRasskazName(storyName);
Set<CatsRelations> catsRelationses = new HashSet<>();
Elements katsInfo = doc.select("a[href*=ras.shtml?kat]");
for (Element kat : katsInfo) {
String katId = kat.attr("href");
CatsNames cat = mainBean.getCat(katId); // Here I got CatsNames from my bean, from table named CatsNames
CatsRelations catsRelations = new CatsRelations();
catsRelations.setCatsNames(cat);
catsRelations.setRasskazi(r);
catsRelationses.add(catsRelations);
}
r.setCatsRelationses(catsRelationses);
r.setRasskazText(textStr);
Session session = sessionFactory.getCurrentSession();
session.save(r);
But Hibernate saves record only in table named rasskazi:
Hibernate:
insert
into
grabberRasskazov.rasskazi
(rasskazName, rasskazText, rasskazDataDobav, rasskazRazmer)
values
(?, ?, ?, ?)
And it doesn't save any data to the table named CatsNames.
Why it doesn't save data to the table CatsNames, why it ignored the code
CatsRelations catsRelations = new CatsRelations();
catsRelations.setCatsNames(cat);
catsRelations.setRasskazi(r);
catsRelationses.add(catsRelations);
}
r.setCatsRelationses(catsRelationses);
?
The problem is that you don't cascade from Parent to Children entities:
<set name="children" inverse="true" cascade="all">
<key column="parent_id"/>
<one-to-many class="Child"/>
</set>
Make sure you add cascade to all one-to-many associations.
I have two tables, A and B. When inserting a new row into table B, how do I insert a FK as a reference to a record in table A?
I've got the two below tables:
--
-- Table structure for table `sector`
--
CREATE TABLE IF NOT EXISTS `sector` (
`sector_id` int(11) NOT NULL AUTO_INCREMENT,
`sector_name` varchar(100) NOT NULL,
`sector_url` varchar(500) NOT NULL,
PRIMARY KEY (`sector_id`),
UNIQUE KEY `sector_id` (`sector_id`,`sector_name`,`sector_url`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
CREATE TABLE IF NOT EXISTS `constituent` (
`constituent_id` int(11) NOT NULL AUTO_INCREMENT,
`constituent_name` varchar(100) DEFAULT '',
`constituent_ticker` varchar(10) NOT NULL,
`constituent_isin_number` varchar(50) DEFAULT '',
`constituent_currency` varchar(10) DEFAULT '',
`sector_id` int(11) NOT NULL,
PRIMARY KEY (`constituent_id`),
KEY `sector_id` (`sector_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
--
-- Constraints for table `constituent`
--
ALTER TABLE `constituent`
ADD CONSTRAINT `constituent_ibfk_1` FOREIGN KEY (`sector_id`) REFERENCES `sector` (`sector_id`);
When I do an insert, how can I structure the query such that when I insert into the table 'constituent', I'm using the primary key of 'sector'?
INSERT into constituent (constituent_name, constituent_ticker, constituent_isin_number, constituent_currency, sectorFK)
values ("the name", "the ticker", "the number", "the currency", "the foreign key???")
To be able to get a primary key value after inserting into table B, in order to insert it into the table A, you could use last_insert_id() function, which when used without a parameter returns a last automatically generated value that was set for an AUTO_INCREMENT column:
For example:
insert into B(col)
values(1);
insert into A(t1_id, col)
values(last_insert_id(), 2);
insert into A(t1_id, col)
values(last_insert_id(), 3);
SQLFIddle Demo
Assuming there is a sector with sector_name 'sector 1' you could do something like this.
INSERT into constituent (constituent_name, constituent_ticker, constituent_isin_number, constituent_currency, sector_id) (select 'the name', 'the ticker', 'the number', 'the currency', sector_id from sector where sector_name = "sector 1");