#GeneratedValue doesn't fetch the value from DB in new session - java

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.

Related

how to insert multi values into one column?

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.

DataException: could not execute query

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

How to make db handle auto insert sequence id postgesql

I had an existed entity (TableEntity.java), the table existed in db, and also the data
Here is how the column id already delcared in TableEntity.java
#Id
#SequenceGenerator(name = "table_name_id_seq", sequenceName = "table_name_id_seq", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "table_name_id_seq")
#Column(name = "id", nullable = false, updateable = false)
private int id;
In the database, I look at the properties of the table, for id column, the data type is int and set as Not NULL
The previous code, for inserting data to db, is only doing "repository.save()"
But now, I want to use PreparedStatement to insert data to db per batch
Here is how I create the query
String query = "INSERT INTO table_name (column1, column2) values (?, ?)";
the problem is, when the query executed, its violates null constraint for the id column. How to make the database can handle my column id? Since, when I just use repository.save() is work fine, but when I use that (could I say it a native query?) query, that exception appear. How to solve this? or any reference to solve this?
Set a default value for the column:
alter table table_name
alter column id set default nextval('table_name_id_seq');
Now if an INSERT statement does not supply a value for the id column (by not mentioning it), the next sequence value is used to populate the column.

JPA - bind entites via primary key - Invalid identifier ORA error

I have the following two tables in my database:
CREATE TABLE ACCOUNT (
ID NUMBER(19, 0) NOT NULL,
AA_ID VARCHAR2(11 CHAR),
BB_ID VARCHAR2(8 CHAR),
STATUS NUMBER(1, 0) DEFAULT 1,
CREATED_AT TIMESTAMP(6) NOT NULL,
LAST_MODIFIED_AT TIMESTAMP(6)
) TABLESPACE $tbsp;
CREATE TABLE MOBILE_INSTANCE (
ID NUMBER(19, 0) NOT NULL,
ACCOUNT_ID NUMBER(19, 0) NOT NULL,
APPLICATION_ID VARCHAR2(36 CHAR) NOT NULL,
TOKEN VARCHAR2(255 CHAR) NOT NULL,
DEVICE VARCHAR2(13 CHAR),
STATUS VARCHAR2(10 CHAR),
CREATED_AT TIMESTAMP(6) NOT NULL,
LAST_MODIFIED_AT TIMESTAMP(6)
) TABLESPACE $tbsp;
And the connection between them:
ALTER TABLE MOBILEBANK_INSTANCE ADD CONSTRAINT FK_MOBILEBANKINSTANCE_ACCOUNT FOREIGN KEY (ACCOUNT_ID) REFERENCES ACCOUNT(ID);
So far, this is working like a charm...
Via JPA, I have created the entites for these tables - please see the following snippet of my entities:
In the MobileInstance entity I have marked the #ManyToOne connection as following:
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "ACCOUNT_ID")
private Account accountId;
And this is how it looks like in my Account entity class:
#OneToMany(mappedBy = "accountId", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
private List<MobileInstance> mobileInstanceList = new ArrayList<>();
As you see, the accountId field (which is in the Account table actually a Long value) is marked as an Account object.
Later on, when I have already an account object, I whish the create a mobileInstance object as well, with the appropiate account ID.
But when I call:
mobileInstance.setAccountId
it requieres an account parameter... When I assigne one to it and try to save it in the DB, I got the error:
ERROR SqlExceptionHelper:131 - ORA-00904: "APPLICATION_ID": invalid identifier
I assume, it is because the Application ID field in the Database is a Number field, and I assigne to it a whole Account object which I do not want to change to Long..
Is there a way the code to recognize that only use the primary key of my Account table?

ActiveJDBC: save() generates insert only for auto-generated primary key?

I recently started using ActiveJDBC. I have the following table (postgresql)
CREATE TABLE users (
id uuid PRIMARY KEY,
email text UNIQUE NOT NULL,
password text,
<some more nullable columns>
created_at timestamp with time zone NOT NULL default (now() at time zone 'utc'),
updated_at timestamp with time zone
);
As you can see, the primary key is of type uuid and has no auto-generate value of any kind.
This is my User class which models the table :
public class User extends Model
{
public User() {
setId(UUID.randomUUID()); // sets value to primary key
}
...
}
This is my attempt to create a new row and insert it :
User u = new User();
System.out.println(u.saveIt());
actually, I expected the insert to fail, since I did not set any value for mandatory email column. However, simply got false as return value. when I turned on logging, I saw that the framework generated an update sql instead of insert:
[main] INFO org.javalite.activejdbc.DB - Query: "UPDATE users SET email = ?, ..., updated_at = ? WHERE id = ?", with parameters: <null>, <null>, <null>, <null>, <null>, <null>, <null>, <2016-01-07 17:30:46.025>, <0621fbdb-5b95-4ee7-a474-8ee9165e2982>, took: 1 milliseconds
so I looked at the save() method inside org.javalite.activejdbc.Model class and saw this piece of code:
if (getId() == null) {
result = insert();
} else {
result = update();
}
does this mean that id column has to be empty in order for an insert to be generated ? if this is true this is unacceptable, so I must be missing something.
#sharonbn, please, see this documentation page: http://javalite.io/surrogate_primary_keys.
ActiveJDBC depends on autogenerated IDs. If the ID == null, the frameworks assumes this is a new record, and generates INSERT statement. If it is non-null, it is assumed the record already exists, and generates UPDATE.
In your case, you will need to explicitly call user.insert() instead of user.saveIt(). This is an 'expert' mode in cases when developers want to be in control of ID management. Further, the method user.update() is private. So for you to insert a new record, you will be calling
user.insert();
and for updates:
user.save();
// or:
user.saveIt();
, depending on what you want.

Categories

Resources