For fail safe am always using double quotes in my mapping class. And this only for PostgreSQL
Here is my class:
#Entity
#Table(name="`Person`"
,schema="public"
)
public class Person implements java.io.Serializable {
private Integer id;
private String name;
private String address;
public Person() {
}
#Id #GeneratedValue(strategy=IDENTITY)
#Column(name="`ID`", nullable=false)
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
#Column(name="`Name`")
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
#Column(name="`Address`")
public String getAddress() {
return this.address;
}
public void setAddress(String address) {
this.address = address;
}
}
When am trying insert using Am getting below exception:
org.postgresql.util.PSQLException: The column nameIDwas not found in this ResultSet.
Query it ran for insert was:
insert into public."Person" ("Address", "Name") values (?, ?)
I can't remove double quotes for other reasons.
Please help me to get this problem fixed.
Update:
Database Schema:
CREATE TABLE "Person"
(
"ID" INTEGER PRIMARY KEY NOT NULL DEFAULT nextval('"Person_ID_seq"'::regclass),
"Name" VARCHAR(255),
"Address" VARCHAR(255)
);
If everything need to be quoted, add the following flags to hibernate.properties or persistence.xml file
hibernate.globally_quoted_identifiers=true
and remove all the single quote from the class Person. However, take note that for Postgresql, placing table/column name etc in double quote effectively turn them into case sensitives. So the case for the table/column in the database must be exact match of the corresponding name in the #Table and #Column annotation.
Related
please help me with this one. I have a very simple crud project with a student table in oracle DB(ID,name,age,email) in springboot and all i want to know is get a student with a method in the jpa repository that calls a stored procedured. when run the project i got an error PLS-00221 is not a procedure or is undefined.
--stored procedure
CREATE OR REPLACE FUNCTION
findstudentbyid
RETURN STUDENT%ROWTYPE
IS
estudiante STUDENT%ROWTYPE;
BEGIN
SELECT *
INTO estudiante
FROM STUDENT
WHERE ID=1;
RETURN estudiante;
END findstudentbyid;
//Entity in sprongboot project
#Entity
#Table
#NamedStoredProcedureQueries({
#NamedStoredProcedureQuery(
name = "findstudentbyid",
procedureName = "findstudentbyid"
)
})
public class Student {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
//Private variables
private Long ID;
private String name;
private Number age;
private String email;
//Constructor
protected Student(){}
public Student(String name , Number age , String email){
this.name = name;
this.age = age;
this.email = email;
}
public Long getID() {
return ID;
}
public String getName() {
return name;
}
public Number getAge() {
return age;
}
public String getEmail() {
return email;
}
}
//JPA CRUD REPOSITORY
public interface StudentRepository extends CrudRepository<Student,Long>{
#Procedure(name = "findstudentbyid")
Iterable<Student> findstudentbyid();
}
You create a function but not a stored procedure.
These objects are different for DB and JPA, try to change your create function to create procedure or change the procedure's call to the function's call signature.
Also, see here for more info about JPA and function call.
I receive an error when trying to query a Postgres DB using JPA.
Student.java:
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
#Entity
public class Student {
#Id
#GeneratedValue
private Long id;
private String name;
private String passportNumber;
public Student() {
super();
}
public Student(Long id, String name, String passportNumber) {
super();
this.id = id;
this.name = name;
this.passportNumber = passportNumber;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassportNumber() {
return passportNumber;
}
public void setPassportNumber(String passportNumber) {
this.passportNumber = passportNumber;
}
}
appliction.properties:
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect
spring.jpa.hibernate.ddl-auto=none
spring.jpa.hibernate.show-sql=true
spring.datasource.url=jdbc:postgresql://localhost:5432/shorten-db
spring.datasource.username=my_user
spring.datasource.password=my_password
spring.datasource.initialization-mode=always
spring.datasource.initialize=true
spring.datasource.schema=classpath:/schema.sql
spring.datasource.continue-on-error=true
appliction.yml:
spring:
datasource:
url: jdbc:postgresql://localhost:5432/shorten-db
username: my_user
password: my_password
driverClassName: org.postgresql.Driver
spring.datasource.schema=classpath:/schema.sql
refers to this schema:
DROP TABLE student;
CREATE TABLE student
(
id varchar(100) NOT NULL,
name varchar(100) DEFAULT NULL,
passportNumber varchar(100) DEFAULT NULL,
PRIMARY KEY (id)
);
When I invoke the service "/students" :
#PostMapping("/students")
public ResponseEntity<Object> createStudent(#RequestBody Student student) {
Student savedStudent = studentRepository.save(student);
URI location = ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}")
.buildAndExpand(savedStudent.getId()).toUri();
return ResponseEntity.created(location).build();
}
I receive the following error:
postgres-db | 2020-08-28 21:46:28.108 UTC [257] HINT: Perhaps you meant to reference the column "student0_.passportnumber".
postgres-db | 2020-08-28 21:46:28.108 UTC [257] STATEMENT: select student0_.id as id1_1_, student0_.name as name2_1_, student0_.passport_number as passport3_1_ from student student0_
How to implement the hint specified in the message Perhaps you meant to reference the column "student0_.passportnumber" I'm not explicitly specifying the SQL and trying to use JPA only. Do I need a custom query or should I modify the student entity ?
JPA expects column names in the form of lower case and each word separated by an underscore. This translates to a camel cased java variable names. In your case, you have java variable name as passportNumber which translates to passport_number. There are three ways this can be solved:
Rename java variable to passportnumber, meaning its a single word. Unfortunately, it doesn't look so good since it breaks the variable naming convention of java.
Rename table column to passport_number, hence making correct JPA connection.
Annotate your java variable with #Column(name="passportNumber").
Recently I have asked a very similar question on Stack overflow which turned out to be a duplicate of another question. In that other question there was a workaround which I applied and solved my problem. Now, this time the workaround doesn't work, and all other mentioned solutions don't work. Also all the solutions from other threads linked to the first thread don't work.
This was my question at first:
SQLServerException: Invalid column name
And this was the duplication:
hibernate column name issues
I have checked the topics on the right in the Linked and Related sections but can't find an solution to my problem. I also cannot comprehend the reason why my problem occurs.
I have 2 tables: Declaration and File (I won't mention my other tables here because they are irrelevant to the problem)
CREATE TABLE [dbo].[Declaration] (
[number] INT NOT NULL,
[status] VARCHAR (50) NOT NULL,
[name] VARCHAR (50) NOT NULL,
[description] VARCHAR (250) NOT NULL,
[amount] FLOAT (53) NOT NULL,
[date] DATE NOT NULL,
[period_id] INT NOT NULL,
[client_project_id] INT NOT NULL,
PRIMARY KEY CLUSTERED ([number] ASC),
CONSTRAINT [fk_client_period] FOREIGN KEY ([client_project_id]) REFERENCES [dbo].[ClientProject] ([number]),
CONSTRAINT [fk_period] FOREIGN KEY ([period_id]) REFERENCES [dbo].[Period] ([number])
);
CREATE TABLE [dbo].[File] (
[number] INT NOT NULL,
[path] VARCHAR (50) NOT NULL,
[declaration_id] INT NOT NULL,
PRIMARY KEY CLUSTERED ([number] ASC),
CONSTRAINT [fk_file] FOREIGN KEY ([declaration_id]) REFERENCES [dbo].[Declaration] ([number])
);
With the corresponding classes:
#Entity
#Table(name = "[file]")
public class File {
#Id
private int number;
private String path;
#ManyToOne(targetEntity = Declaration.class)
private int declaration_id;
public int getDeclaration_id() {
return declaration_id;
}
public void setDeclaration_id(int declaration_id) {
this.declaration_id = declaration_id;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
}
And
#Entity
public class Declaration {
#Id
private int number;
private String status;
private String name;
private String description;
private double amount;
private Date date;
private int period_id;
private int client_project_id;
#OneToMany(targetEntity = File.class,mappedBy = "declaration_id",orphanRemoval = true)
private List<File> files = new ArrayList<>();
public List<File> getFiles() {
return files;
}
public void setFiles(List<File> files) {
this.files = files;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number= number;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public double getAmount() {
return amount;
}
public void setAmount(double amount) {
this.amount = amount;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
public int getPeriod_id() {
return period_id;
}
public void setPeriod_id(int period_id) {
this.period_id = period_id;
}
public int getClient_project_id() {
return client_project_id;
}
public void setClient_project_id(int client_project_id) {
this.client_project_id = client_project_id;
}
}
I have defined my #ManyToOne and #OneToMany relations based on these topics and tutorials:
https://vladmihalcea.com/a-beginners-guide-to-jpa-and-hibernate-cascade-types/
JPA JoinColumn vs mappedBy
What I want: Delete Declaration, automatically delete files related to the declaration
What I get: Invalid column name 'declaration_id_number'.
What I have tried:
- renaming fields in database to declaration_id_number (results in declaration_id_number_number)
- using #Column(name="declaration_id") on declaration_id field
- using #Colum(name="declaration_id") on the getter field
- using #JoinColumn(name="fk_file") on the declaration_id field
- Using different kinds of naming stategies (in application.properties), including the default one
spring.jpa.hibernate.naming.strategy: org.hibernate.cfg.EJB3NamingStrategy
spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
The actual SQL query:
select files0_.declaration_id_number as declarat3_3_0_, files0_.number as number1_3_0_, files0_.number as number1_3_1_, files0_.declaration_id_number as declarat3_3_1_, files0_.path as path2_3_1_ from [file] files0_ where files0_.declaration_id_number=?
select declaratio0_.number as number1_2_0_, declaratio0_.amount as amount2_2_0_, declaratio0_.client_project_id as client_p3_2_0_, declaratio0_.date as date4_2_0_, declaratio0_.description as descript5_2_0_, declaratio0_.name as name6_2_0_, declaratio0_.period_id as period_i7_2_0_, declaratio0_.status as status8_2_0_ from declaration declaratio0_ where declaratio0_.number=?
I am running Spring boot with JPA Hibernate 5.2.10
Is there anyone out there who knows why this happends, if I know why it happends I might be able to fix the problem my self. Right now I am completely stuck.
Thanks in advance.
EDIT:
Ok, so by accident I solved my own problem, I still don't know why the problem occured in the first place. According to this answer(s) of this topic:
JPA JoinColumn vs mappedBy
You use #ManyToOne & #OnyToMany
In my case I don't need to use #ManyToOne in the File class. I only need #OneToMany in my Declaration class. No more errors occur after I removed this annotation.
If anyone knows the reason for this problem, please provide an answer so that it can be of use in the future for me or someone else.
In my case I don't need to use #ManyToOne in the File class. I only need #OneToMany in my Declaration class. No more errors occur after I removed this annotation.
I don't think that this will work. If you remove the #ManyToOne annotation, the persistence provider will create a join table by default to maintain the relationship. What you mean is probably that you don't get any exception. But look at the database schema:
CREATE TABLE [dbo].[File] (
[number] INT NOT NULL,
[path] VARCHAR (50) NOT NULL,
[declaration_id] INT NOT NULL,
PRIMARY KEY CLUSTERED ([number] ASC),
CONSTRAINT [fk_file] FOREIGN KEY ([declaration_id]) REFERENCES [dbo].[Declaration] ([number])
);
declaration_id is declaraed to be NOT NULL which means you cannot save anything in this table unless you assign it an entry in the Declaration table.
You have defined a foreign key constraint which means your database will check this when you save a file record.
This means that you have two options:
you need an #ManyToOne annotation so that JPA can map the entities correctly and automatically that will correspond to your database schema, or
you remove the foreign key field declaration_id and the corresponding referential integrity constraint from the File table. In this case, the persistence provider will create a join table by default for you, unless you customize it.
So if you want to use the first option, i.e. #ManyToOne annotation, you have to map the entities as follows:
#Entity
#Table(name = "[file]")
public class File {
#Id
private int number;
private String path;
#ManyToOne
#JoinColumn(name = "declaration_id")
private Declaration declaration;
public int getDeclaration_id() {
return declaration_id;
}
// ... getters and setters
}
and a slightly modified Declaration entity:
#Entity
public class Declaration {
#Id
private int number;
// ... other fields
#OneToMany(mappedBy = "declaration",orphanRemoval = true)
private List<File> files = new ArrayList<>();
// ... Rest of the code
}
Notes:
I removed targetEntity = File.class attribute from the annotation because you don't need it as your collection already implies the type.
Why are you putting table/column names into the square brackets? They make the code unreadable and I don't see the benefit of using it.
I already have such an error, when you try to perform unapropriate matching (date to boolean, and so) which I had been able to fix quite easilly.
But this time, I am quite confused, because hibernate refuses to match a "numeric" Id to a Java "Long" (and it also failed when setter is made for Double, Integer, Float, String, int, long, etc.)
The sql-server field "id" is a NUMERIC(19,0)
My DTO is :
#XmlRootElement
#XmlAccessorType(XmlAccessType.PROPERTY)
public class DtoResult {
private Long id;
private String name;
// ...
public Long getId() {
return id;
}
public void setId(final Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(final String name) {
this.name = name;
}
}
My hibernate query :
final SQLQuery query= getCurrentSession().createSQLQuery(select + from + where);
query.setParameter("manyFields", manyFields);
query
.addScalar("id")
.addScalar("name")
.setResultTransformer(Transformers.aliasToBean(DtoResult.class));
return query.list(); // List<DtoResult>
Error:
IllegalArgumentException occurred while calling setter for property [com.some.thing.DtoResult.id (expected type = java.lang.Long)]; target = [com.some.thing.DtoResult#77a70b79], property value = [269895]
I am really puzzled about this, thus any help is welcome.
Thanks for reading untill there.
Just add the expected type, like:
.addScalar("id", new LongType())
.addScalar("name", new StringType())
The number from database query is not Long but BigInteger.
Change setter to:
public void setId(final Number id) {
this.id = id != null ? id.longValue() : null;
}
I am practice Hibernate with the following classes and a MySQL database.
#Entity
#Table(name="Student")
public class Student {
#Id
#GeneratedValue
private int student_id;
private String student_name;
#ManyToOne(cascade=CascadeType.ALL)
private StudentAddress address;
#Transient
#Temporal(TemporalType.DATE)
private Date birthDay;
public Student() {
}
public Date getBirthDay() {
return birthDay;
}
public void setBirthDay(Date birthDay) {
this.birthDay = birthDay;
}
public int getStudent_id() {
return student_id;
}
public void setStudent_id(int rollNo) {
this.student_id = rollNo;
}
public String getStudent_name() {
return student_name;
}
public void setStudent_name(String name) {
this.student_name = name;
}
public StudentAddress getAddress() {
return address;
}
public void setAddress(StudentAddress address) {
this.address = address;
}
}
#Entity
#Table(name="student_address")
public class StudentAddress {
#Id
#GeneratedValue
private int address_id;
private String address_detail;
public int getAddress_id() {
return address_id;
}
public void setAddress_id(int address_id) {
this.address_id = address_id;
}
public String getAddress_detail() {
return address_detail;
}
public void setAddress_detail(String address_detail) {
this.address_detail = address_detail;
}
}
I keep getting the following error message from these sql statements:
Hibernate: insert into student_address (address_detail) values (?)
Hibernate: insert into Student (address_address_id, student_name) values (?, ?)
Error Message:
Unknown column '**address_address_id'** in 'field list'
My database has the field name address_id.
Hibernate keeps appending address to address_id and changes the column name. I could probably change the field name from address to address_address_id in my database but what is causing this to happen. Is it a valid behavior in Hibernate and can I change it?
That's the default column name Hibernate uses for #ManyToOne association:
Default (only applies if a single join column is used): The
concatenation of the following: the name of the referencing
relationship property or field of the referencing entity or embeddable
class; "_"; the name of the referenced primary key column. If there is
no such referencing relationship property or field in the entity, or
if the join is for an element collection, the join column name is
formed as the concatenation of the following: the name of the entity;
"_"; the name of the referenced primary key column.
To specify the desired column name:
#ManyToOne(cascade=CascadeType.ALL)
#JoinColumn(name="address")
private StudentAddress address;