I have a question of mysql java pojo. I try to insert multi values into one column. But the code throws null values. These sql queries are used not on jpa, but r2dbc spring webflux. As you know table realtionship is not supported in r2dbc driver, so I try to insert the values directly to each tables.
First I make pojo codes.
#Data
#AllArgsConstructor
#NoArgsConstructor
#Builder
#Table
public class Post {
#Id
#Column("post_id")
private Long postId;
#Column
private String title;
#Column
private String body;
#Column("tag_id")
private Collection<Long> tagId; // value of tagId is null
}
#Data
#AllArgsConstructor
#NoArgsConstructor
#Builder
#Table
public class Tag {
#Id
#Column("tag_id")
private Long tagId;
#Column
private String body;
#Column("post_id")
private Long postId;
}
And I execute the bleow SQL statments
CREATE TABLE IF NOT EXISTS post (
post_id BIGINT NOT NULL AUTO_INCREMENT,
title VARCHAR(30) NOT NULL,
body TEXT,
PRIMARY KEY (post_id)
);
CREATE TABLE IF NOT EXISTS tag (
tag_id BIGINT NOT NULL AUTO_INCREMENT,
body VARCHAR(255),
post_id BIGINT NOT NULL,
PRIMARY KEY (tag_id),
CONSTRAINT tag_ibfk_1 FOREIGN KEY (post_id) REFERENCES post (post_id) ON DELETE CASCADE
);
The table relationship of post and tag table is one to many, Below codes are the sql insert codes.
INSERT INTO post (post_id, title, body) VALUES (1, 2, 'Title 1', 'post #1 body');
INSERT INTO post (post_id, title, body) VALUES (2, 2, 'Title 2', 'post #2 body');
INSERT INTO tag (tag_id, post_id, body) VALUES (1, 1, 'first tag');
INSERT INTO tag (tag_id, post_id, body) VALUES (2, 1, 'second tag');
INSERT INTO tag (tag_id, post_id, body) VALUES (3, 2, 'third tag');
INSERT INTO tag (tag_id, post_id, body) VALUES (4, 2, 'last tag');
The above SQL statements are executed when the project starts.
The 'tagId' member variable of 'post' java class has java Collection type which means having multi tag values.
But when the response of reactive web returns, the tag values are null.
http://localhost:8080/route/post/all
[{"postId":1,"title":"Title 1","body":"post #1 body","tagId":null},{"postId":2,"title":"Title 2","body":"post #2 body","tagId":null}]
How can I insert multiple tag_id values of tag class into post.tagId? Any idea?
You can't link the tags table directly in R2DBC. Another way of doing it is executing two queries at once. Since I have no idea what your endpoint looks like here is my implementation of it:
TagRepository:
public interface TagRepository extends ReactiveCrudRepository<Tag, Integer> {
Flux<Tag> getTagsByPostId(#Param("post_id") Integer postId);
}
PostRepository:
public interface PostRepository extends ReactiveCrudRepository<Post, Integer> {
}
Then to get a posts tags you can just execute two queries at once when you have the post id:
Mono.zip(tagRepository.getTagsByPostId(postID).collectList(),
postRepository.findById(postID));
After doing that the Mono.zip function returns a Tuple<List<Tag>, Post>. You can then use tuple.getT1() to get the list of tags and tuple.getT2() to get the post.
Related
I get this error when I try to run start my application:
org.springframework.dao.DataIntegrityViolationException: could not execute query; SQL [SELECT * FROM testquestions ORDER by id DESC LIMIT 1]; nested exception is org.hibernate.exception.DataException: could not execute query
As seen in previous problems on StackOverflow, I tried to adjust the length of my data input in my sql file and I've set the length of my #Column to the same amount of characters. this didn't help.
this is my #Table class:
#Entity
#Getter
#Setter
#Table(name = "testquestions")
public class TestQuestion {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(name = "questiontitle", length = 2000)
private String questionTitle;
#Column(name = "info", length = 4096)
private String Info;
#Column(name = "solvetime")
private int solveTime;
#Column(name = "difficultylevel")
private DifficultyLevel difficultyLevel;
#Column(name = "questionimage")
private Image questionImage;
public TestQuestion(){
}
public TestQuestion(int id, String questionTitle, String info, DifficultyLevel difficultyLevel) {
this.id = id;
this.questionTitle = questionTitle;
Info = info;
this.difficultyLevel = difficultyLevel;
}
public String getInfo() {
return Info;
}
}
This is my # Query in my QuestionRepository:
#Query(value = "SELECT * FROM testquestions ORDER by id DESC LIMIT 1", nativeQuery = true)
TestQuestion fetchLastQuestion();
This is my database.sql file, it writes to a PostgreSQL data base:
TRUNCATE TABLE users CASCADE;
TRUNCATE TABLE testquestions CASCADE;
DROP TABLE users;
DROP TABLE testquestions;
CREATE TABLE users(
id int,
username varchar(255),
password varchar(255),
role varchar(255)
);
CREATE TABLE testquestions(
id int primary key ,
questiontitle varchar(2000),
info varchar(4096),
solvetime int,
difficultylevel varchar(255),
questionimage bytea
);
INSERT INTO users(id, username, password, role)
VALUES (0, 'user', 'u', 'user'),
(1, 'user','u','user');
INSERT INTO testquestions(id,questiontitle, info, solvetime, difficultylevel, questionimage)
VALUES (0, 'Multiple Databases', 'A company wants to use Spring Boot in a web application which should use JPA as a database abstraction. The unit tests should be run on an H2 database while the production should run on a MySQL database.
Select all the things that need to be done or that will be done automatically by Spring Boot.', 3, 'Easy',
''),
(1, 'Screen Orientation', 'Which of these methods are called when the screen changes orientation from portrait to landscape in Android?',
3, 'Easy',''),
(2, 'Merge Names', 'Implement the uniqueNames method. When passed two arrays of names, it will return an array containing the names that appear in either or both arrays. The returned array should have no duplicates.
For example, calling MergeNames.uniqueNames(new String[]{''Ava'', ''Emma'', ''Olivia''}, new String[]{''Olivia'', ''Sophia'', ''Emma''}) should return an array containing Ava, Emma, Olivia, and Sophia in any order.',
10, 'Easy',''),
(3, 'Date', 'Write a function that converts user entered date formatted as M/D/YYYY to a format required by an API (YYYYMMDD). The parameter "userDate" and the return value are strings.
For example, it should convert user entered date "12/31/2014" to "20141231" suitable for the API.', 10, 'Easy', ''),
(4, 'Inspector', 'Fix the bugs in the following HTML code.', 10, 'Easy',''),
(5, 'Train Composition', 'A TrainComposition is built by attaching and detaching wagons from the left and the right sides, efficiently with respect to time used.
For example, if we start by attaching wagon 7 from the left followed by attaching wagon 13, again from the left, we get a composition of two wagons (13 and 7 from left to right). Now the first wagon that can be detached from the right is 7 and the first that can be detached from the left is 13.
Implement a TrainComposition that models this problem.', 20, 'Hard', '');
Has anyone got an idea how to fix this error?
Thanks!
Tom
Using
Hibernate 5.3, Spring Boot 2.1, MySQL, that runs in Windows 10 OS.
What I know
I have verified on my phpmyadmin the case of the attributes. And as long the case were the same as the attributes of my Entity class you don't have to explicitly define the column name in that Entity. And using #Column(name="tableattribute") is not required.
Problem
Once I executes the query, the number of row has been retrieved correctly. For example, my database contains 5 record, the List contains 5 employee objects, but all its attributes of the Entity always returns as null value.
I want to remove explicitly declaring the column name on each attribute and ensure that it will work in the actual server which might cause problem with the case of column name and the attribute name.
Tried
I tried to add #Column('column Name all lowercase') on each attributes and It retrieve the value.
Upon learning this, I verified the table column if it is lower case, but is not in lower case. Instead, It still follow the camel-case that is in my SQL command to create the table.
MySQL Table
CREATE TABLE `personal` (
`empID` int(11) NOT NULL,
`empNumber` varchar(15) CHARACTER SET latin1 COLLATE latin1_bin NOT NULL DEFAULT '',
`surname` varchar(50) NOT NULL DEFAULT '',
`firstname` varchar(50) NOT NULL DEFAULT '',
`middlename` varchar(50) NOT NULL DEFAULT '',
`middleInitial` varchar(10) DEFAULT NULL,
`nameExtension` varchar(10) DEFAULT '',
`salutation` varchar(15) NOT NULL DEFAULT ''
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
Entity
This Entity is now working fine as long as #Column and specify the column name in lowercase. But it is annoying to add each attribute with #Column and specify the name of the field in all lower case.
#Entity
#Table(name="personal")
public class Employee implements Serializable {
#Id
#Column(name="empID")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#NotNull
#Column(name="empnumber")
private String empNumber;
private String surname;
private String firstname;
private String middlename;
#Column(name="middleinitial")
private String middleInitial;
#Column(name="nameextension")
private String nameExtension;
}
Actual Query Snippet on DAO
#Autowired
private EntityManager entityManager;
#Override
public List<Employee> findAll() {
Session currentSession = entityManager.unwrap(Session.class);
Query<Employee> query = currentSession.createQuery("from Employee", Employee.class);
return query.getResultList();
}
You can change that behavior by setting
spring.jpa.hibernate.naming.physical-strategy
spring.jpa.hibernate.naming.implicit-strategy
properties in your application.properties. On how to implement the strategies yourself, you can check out official docs.
Edit 1:
spring.jpa.hibernate.naming.physical-strategy = org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
spring.jpa.hibernate.naming.implicit-strategy = org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl
My requirement is to make hibernate fetch the latest value for PI already available in existing table and add new record by incrementing the the max PI value by one.
Below is my Entity class implementation
#Entity
public class User {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private Integer id;
private String name;
}
Below is my class through which I enter value in User table
#PostMapping("/jpa/users")
public void addUser(#Valid #RequestBody User user)
{
User saved = userRepository.save(user);
}
My user table already has below values before I start my application
id name
1 sample_name_1
2 sample_name_2
Now when I start my application and try inserting new value in User table it should enter new record with PI as 3
Example: Below is JSON request body (Input)
{
"name": "sample_name_3"
}
It gives the below error
{
"timestamp": "2018-05-01T23:09:31.806+0000",
"status": 500,
"error": "Internal Server Error",
"message": "could not execute statement; SQL [n/a]; constraint [\"PRIMARY KEY ON PUBLIC.USER(ID)\"; SQL statement:\ninsert into user (name, id) values (?, ?) [23505-197]]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement",
"path": "/jpa/users"
}
I understand it is having PrimaryIndex contraint error. It is trying to insert new record with PI as 1
If my user table is empty and when I insert couple of records, it adds new auto-incremented values.
So, I think Hibernate is not reading the latest value of id column from user table.
What annotation should I used to make hibernate read the latest value of id everytime before inserting new record.
PS: I've already tried below strategy and none of it works
GenerationType.TABLE
GenerationType.AUTO
GenerationType.SEQUENCE
GenerationType.IDENTITY
The generation type you want to use is GenerationType.IDENTITY, however you need to
use a database which supports identity columns, and
correctly define your primary key column to be an identity column.
So for example in PostgreSQL, you would define your primary key column like this:
CREATE TABLE mytable (
id serial primary key,
...
Definitive information about this is available in the JPA specification under section 11.1.20 GeneratedValue Annotation.
I have to create for test reason tables in SQL format.
They should be loaded for the test set up.
And after it, Service and DAO layer should be tested.
I have stuck at creating middle for Entities.
Here is User class:
public class User {
private Integer id;
private String name;
private Calendar birthday;
private String email;
private String role;
private Set<Ticket> bookedTickets = new HashSet<>();
It contains a Set of Tickets.
Here is Ticket POJO:
public class Ticket {
private Integer id;
private Event event;
private Double price;
private User user;
It has User and Event instances.
If Ticket isn't assigned to any User (user == null) => it is free. If is => it is purchased.
Event and Auditorium POJO:
public class Event {
private Integer id;
private String name;
private Double price;
private EventRating eventRating;
private Set<Calendar> eventDateTime;
public class Auditorium {
private Integer id;
private String name;
private Integer numberOfSeats;
private Set<Integer> vipSeats;
Event has Set of available dates, coz some event can be repeated during one day few times.
Getters and setters were omitted at code snippets.
Here is my create-db.sql script:
----------------------
-- Create Users table
----------------------
CREATE TABLE Users (
user_id INTEGER PRIMARY KEY NOT NULL,
user_name VARCHAR(30) NULL,
user_birthday DATETIME NULL,
user_email VARCHAR(30) NULL,
user_role VARCHAR(20) NULL,
user_tickets VARCHAR(100) NULL, -- Here should be collection of objects
);
----------------------
-- Create Events table
----------------------
CREATE TABLE Events (
event_id INTEGER PRIMARY KEY NOT NULL,
event_name VARCHAR(30),
event_price DECIMAL(8,2),
event_rating VARCHAR(30),
event_date DATETIME,
);
---------------------------
-- Create Auditoriums table
---------------------------
CREATE TABLE Auditoriums (
aud_id INTEGER PRIMARY KEY NOT NULL,
aud_name VARCHAR(30),
aud_seats INTEGER,
aud_vip INTEGER,
);
-----------------------
-- Create Tickets table
-----------------------
CREATE TABLE Tickets (
tick_id INTEGER PRIMARY KEY NOT NULL,
event_id VARCHAR(30),
tick_price DECIMAL(8,2),
user_id INTEGER,
);
here is insert-data.sql:
------------------------
-- Populate Users table
------------------------
INSERT INTO Users VALUES (1, 'Garry Potter', '2001-05-01', 'potter#gmail.com', 'admin', NULL);
INSERT INTO Users VALUES (2, 'Ron Weasley', '2000-05-01', 'ron#gmail.com', 'user', NULL);
INSERT INTO Users VALUES (3, 'Germiona Grendjer', '2000-05-01', 'germiona#gmail.com', 'user', NULL);
------------------------
-- Populate Events table
------------------------
INSERT INTO Events (event_id, event_name, event_price, event_rating, event_date)
VALUES (1, 'Green Mile', 60.0, 'high', '2016-02-28');
INSERT INTO Events (event_id, event_name, event_price, event_rating, event_date)
VALUES (2, 'Gone by the wind', 50.0, 'middle', '2016-02-28');
I am using Spring JDBC for working with DB.
How to manage saving Set<Ticket> and Set<Calendar> with SQL script and support their unique as well?
I have a table, which has a column "description" of type TEXT. If I do:
SELECT id, description FROM table_name;
I see in "description" column instead of text value a number. Is there any way to see the text value?
Edit: After some testing I found out why I see numbers, but others like Craig see real text. It's because the data are inserted using Hibernate.
Entity:
#Entity
public class Settings {
#Id
#GeneratedValue
private Integer id;
#Column(nullable = false, unique = true)
private String key;
#Lob
#Column(nullable = false, length = Integer.MAX_VALUE)
private String value;
// getters and setters
}
Log result:
Hibernate: create table Settings (id int4 not null, key varchar(255) not null, value text not null, primary key (id));
Hibernate: select nextval ('hibernate_sequence')
Hibernate: insert into Settings (key, value, id) values (?, ?, ?)
16:05:32,718 TRACE BasicBinder:81 - binding parameter [1] as [VARCHAR] - [GoogleSiteVerification]
16:05:32,718 TRACE BasicBinder:81 - binding parameter [2] as [CLOB] - []
16:05:32,726 TRACE BasicBinder:81 - binding parameter [3] as [INTEGER] - [4]
If I do in pgAdmin3 this select:
select * from settings;
I see this result:
1;"GoogleSiteVerification";"112351"
Added #Type(type = "org.hibernate.type.TextType") to attribute annotated with #Lob. Now it works as desired.
Also it solved the issue with encoding, which was the reason I opened pgAdmin in the first place (to see what's inside).
Technical detail: PostgreSQL stored LOB in separate place and referenced it by a numerical identifier (which was what the number which confused me).
Setup:
CREATE TABLE table_name (id integer, description text);
INSERT INTO table_name(id, description) values (1, '12');
Demo:
testdb=> SELECT id, description FROM table_name;
id | description
----+-------------
1 | 12
(1 row)
Yup, I'd say you have a number in your description column because there's a number in your description column.