In MySQL I have script that create table
create table account (
AccountId int not null auto_increment,
Login varchar(31),
Password varchar(31),
primary key (AccountId)
);
In java class i have model to this table
#Entity
#Table(name = "account")
public class Account {
#Column(name = "AccountId", nullable = false, unique = true)
private Integer AccountId;
private String Login;
private String Password;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
public Integer getAccountId() {
return AccountId;
}
In Repository package
public interface AccountRepository extends JpaRepository<Account, Integer> {
Account findAccountByLoginAndPassword(String login, String password);
}
In client site i try send in request login and password but i have error in server site
2018-05-28 14:46:15.464 INFO 20300 --- [nio-8080-exec-2] o.h.h.i.QueryTranslatorFactoryInitiator : HHH000397: Using ASTQueryTranslatorFactory
Hibernate: select account0_.account_id as account_1_0_, account0_.login as login2_0_, account0_.password as password3_0_ from account account0_ where account0_.login=? and account0_.password=?
`ERROR 20300 --- [nio-8080-exec-2] o.h.engine.jdbc.spi.SqlExceptionHelper : Unknown column 'account0_.account_id' in 'field list`
'
That mean I should change my column name in MySQL table to account_id?
"That means I should change my column name in MySQL table to account_id"
Yep, this is a good idea because of naming convention, but also you can configure proper naming strategy:
spring.jpa.hibernate.naming_strategy=org.hibernate.cfg.EJB3NamingStrategy
Or you can try to print your column name in lower case. (If your MySQL is Windows based)
#Column(name="accountid", nullable = false, unique = true)
Use #Column(name="accountid", nullable = false, unique = true)
Columns in Mysql are case insensitive. If you use case sensitive column name in #Column then it will convert camel case to snake case.
With Hibernate5 and Spring boot 1.5 or higher, If you still get "unknown column" error even after using PhysicalNamingStrategyStandardImpl as naming strategy, try using #Column mapping on getter method of the field instead of property level #column mapping.
Related
In a project with Spring Boot 2.0.0.RELEASE, when I start the application the first time, when the database tables are being created, I'm getting the following warning message:
Hibernate: alter table if exists bpermission drop constraint if exists UK_qhp5om4s0bcb6j0j8pgcwitke
2018-03-14 11:32:03.833 WARN 15999 --- [ restartedMain] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Warning Code: 0, SQLState: 00000
2018-03-14 11:32:03.833 WARN 15999 --- [ restartedMain] o.h.engine.jdbc.spi.SqlExceptionHelper : constraint "uk_qhp5om4s0bcb6j0j8pgcwitke" of relation "bpermission" does not exist, skipping
Notice the constraint name -> uk_qhp5om4s0bcb6j0j8pgcwitke
...and below I'm seeing this being logged:
Hibernate: alter table if exists bpermission add constraint UK_qhp5om4s0bcb6j0j8pgcwitke unique (label)
Hibernate: alter table if exists bpermission drop constraint if exists UK_ow4uw3orjjykeq869spvqtv6u
From the previous message we can see Hibernate is adding the constraint UK_qhp5om4s0bcb6j0j8pgcwitke, the same as the one shown in the warning but the first letter is uppercase. This is related to the unique constraint in the label property (see class below).
The (possible) involved entities in getting this warning are:
BPermission
#Data
#NoArgsConstructor(force = true)
#RequiredArgsConstructor
#EqualsAndHashCode(callSuper = true, exclude = "roles")
#ToString(callSuper = true, exclude = "roles")
#Entity
public class BPermission extends GmsEntity {
#NotNull()
#NotBlank()
#Size(max = 255)
#Pattern(regexp = "someDefinedRegexp")
#Column(unique = true, nullable = false, length = 255)
private final String name;
#NotNull()
#NotBlank()
#Size(max = 255)
#Column(unique = true, nullable = false, length = 255)
private final String label;
#ManyToMany(mappedBy = "permissions")
private Set<BRole> roles;
}
BPermission is related (in case this info helps in any way) to
BRole
#Data
#NoArgsConstructor(force = true)
#RequiredArgsConstructor
#EqualsAndHashCode(callSuper = true, exclude = "permissions")
#ToString(callSuper = true, exclude = {"description", "permissions"})
#Entity
public class BRole extends GmsEntity{
#NotNull()
#NotBlank()
#Size(max = 255)
#Pattern(regexp = "someDefinedRegexp"))
#Column(unique = true, nullable = false, length = 255)
private final String label;
#Size(max = 10485760)
#Column(length = 10485760)
private String description;
private Boolean enabled = false;
#ManyToMany
#JoinTable(
name = "brole_bpermission",
joinColumns = #JoinColumn(name = "brole_id"),
inverseJoinColumns = #JoinColumn(name = "bpermission_id")
)
private Set<BPermission> permissions;
public void addPermission(BPermission... p) {
// code for adding permissions
}
public void removePermission(BPermission... p) {
// code for removing permissions
}
public void removeAllPermissions() {
// code for removing permissions
}
They are mapped to a PostgreSQL9.5.11 database as follow:
The related spring configurations are:
spring.datasource.url = jdbc:postgresql://127.0.0.1/mydbname
spring.datasource.username = postgres
spring.datasource.password = postgres
spring.datasource.driver-class-name = org.postgresql.Driver
spring.jpa.hibernate.ddl-auto = update
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation = true
spring.jpa.open-in-view = false
I'm getting the mentioned warning message for all entities with properties which are annotated with #Column(unique = true)
Question
Why is this warning being thrown? Maybe... a bug?
How can I get rid of it?
Of course, a warning sometimes is not bad at all, but I feel here this is either unnecessary or it is indicating that "something should be done differently" despite SQLCode 0000 means "successful_completion".
PS: I'm using Lombok.
Spring Boot 2.0 (Hibernate 5?) apparently uses DROP_RECREATE_QUIETLY as unique constraint update strategy which is really wrong as a default option, because simply what it does each time you start the app is removing the unique index and creating it again. If you work on databases with some (a lot of?) data I can imagine how slow will be the start of everything with this option.
In such scenario, when you start on empty database, operation of removing the index generates warning which you can see in the logs. When you start again, the warning dissapears but it silently does the expensive operation of recreating index.
To disable this you need to switch the strategy back to RECREATE_QUIETLY with following params:
# for plain hibernate
hibernate.schema_update.unique_constraint_strategy=RECREATE_QUIETLY
# for spring data
spring.jpa.properties.hibernate.schema_update.unique_constraint_strategy=RECREATE_QUIETLY
This looks like a bug.
I'd recommend you to create the schema via higher-level migration tools like flywaydb and let hibernate only validate the generated schema. It is integrated to spring-boot and it is very easy to setup, see the documantation and examples.
The benefit is that you have full control on the schema, you don't have unexpected schema changes while upgrading hibernate.
Usually automatical schema generation is used only during development, but not in production. You can find more details on why it is so important here.
Having such setup you might let hibernate generate the schema only in development mode, but flighway will take responsibility for the rest of the cases.
I have a model class that is mapped to a postgres database using hibernate. My model class is:
#Entity
#Table(name="USER")
public class User {
#Id
#GeneratedValue
#Column(name="id")
private long id;
#Column(name="username", unique=true)
private String username;
#Column(name="email")
private String email;
#Column(name="created")
private Timestamp created;
public User(long id, String username, String email) {
this.id = id;
this.username = username;
this.email = email;
}
}
I try to retrieve the user with username "adam" using the below query:
tx = session.beginTransaction();
TypedQuery<User> query = session.createQuery("FROM User u WHERE u.username = :username", User.class).setParameter("username", "adam");
user = query.getSingleResult();
I get an exception that says:
org.postgresql.util.PSQLException: ERROR: column user0_.id does not exist
My database from bash shell looks like:
How does hibernate map class attributes to table columns? Does it match based on the #Column(name="username") only or does it also try to match based on datatypes and constraints such as unique/auto-increment?
Solution
In PostgreSQL you have to specify the name of schema like so :
#Table(name="table_name", schema = "myapp")
^^^^^^^^^^^^^^^^
Long Story
you got this error :
org.postgresql.util.PSQLException: ERROR: column user0_.id does not exist
because when you create a database in PostgreSQL, it create a default schema named public, so when you don't specify the name in the Entity then Hibernate will check automatically in the public schema.
Good practices
Don't use Upper letters in the name of database, schema, tables or columns in PostgreSQL. Else you should to escape this names with quotes, and this can cause Syntax errors, so instead you can use :
#Table(name="table_name", schema = "schema_name")
^^^^^^^^^^ ^^^^^^^^^^^
the keyword USER is reserved keyword in PostgreSQL take a look at
+----------+-----------+----------+-----------+---------+
| Key Word |PostgreSQL |SQL:2003 | SQL:1999 | SQL-92 |
+----------+-----------+----------+-----------+---------+
| .... .... .... .... .... |
+----------+-----------+----------+-----------+---------+
| USER | reserved |reserved | reserved | reserved|
+----------+-----------+----------+-----------+---------+
to difference between Dto and Entity its good practice to use Entity in the end of the name of your Entity for example UserEntity
For people getting this exception ,In postgres Whenever you write an Entity Class try to associate it with the correct schema (where your table is present), like this:
#Entity
#Table(name = "user", schema = "users_details")
public class User implements Serializable{
#Column(name = "id")
Long id; //long is not recommended
// Other data
}
As #YCF_L has said Don't use Upper_case letters in a table name or column name otherwise you will get this exception.
This convention becomes more important when their is a scenario where you have to auto generate the tables from entity classes or vice-versa.
Should add schema name on the Entity class.
For this example, when the schema name is public
#Table(name = "user", schema = "public")
See the PostgreSQL Admin view below
See here for more about SpringBoot Java and Postgre SQL connectivity:
https://cmsoftwaretech.wordpress.com/2020/04/25/springboot-thymleaf-using-postgresql/
I obtained using general names like user are making troubles in the app.
I got the same issue as reported here with the following simple entity.
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;
#Entity
public class User implements Serializable {
private static final long serialVersionUID = 6843302791607583447L;
#Id
#SequenceGenerator(name = "user_id_seq", sequenceName = "user_id_seq", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "user_id_seq")
private Long id;
#Column
private String name;
#Column
private String password;
#Override
public String toString() {
return name;
}
public Long getId() {
return id;
}
public String getName() {
return name;
}
public void setName(final String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(final String password) {
this.password = password;
}
}
All i did was renaming the entity from User to Sessionxuser (and renaming the datatable from user to sessionxuser to fix this issue.
Schema was still public.
Since pre- or postfix some names like mycoolappuser or usermycoolapp to avoid troubles like this.
Find below a list with reserved keywords and literals preventing using as table, column, and further customized names.
https://www.postgresql.org/docs/8.1/sql-keywords-appendix.html
In this case user is preserved for PostgreSQL, SQL:2003, SQL:1999 and SQL-92.
Try Dropping the table from pg admin console (drop table schema_name.table_name)and make sure your entity class is proper annotated.For example #Table(name = "table_name", schema = "schema_name") on entity class
Use: #GeneratedValue(strategy = GenerationType.IDENTITY)
In your POJO class Id Field. This thing solved my error.
In addition to all previous correct answers, I'd like to say that the positioning of annotations #Column and #GeneratedValue also matters. You want to have both these annotations above either the specific field or getter method, but not separately (not one annotation above the getter and the other above the field). It worked for me at least.
I fixed the issue by altering the column name from nameLikeThis to name_like_this
ALTER TABLE table RENAME nameLikeThis to name_like_this;
I am using Spring mvc with hibernate and i have a lookup table in my SQL server database. this table has 4 columns
#Entity
#Table(name = "VLE_LOOKUP_DATA")
public class Lookup_Data{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long ID;
#Column(name = "ENTITYNAME")
private String ENTITYNAME;
#Column(name = "CODE")
private String CODE;
#Column(name = "DESCRIPTION")
private String DESCRIPTION;
}
This table has one to one relationship with multiple tables for example with student table.
#Entity
#Table(name = "STUDENT")
public class student{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long STUDENT_ID;
#OneToOne
#JoinColumn(name = "DEPARTMENT_ID")
private Lookup_Data DEPARTMENT_ID;
#Column(name = "Name")
private String Name;
#OneToOne
#JoinColumn(name = "GENDER_ID")
private Lookup_Data GENDER_ID;
}
Here the foreign key came from Lookup Table is not the Primary key(ID) of Lookup data.its column name CODE which is referenced as foreign key in other tables.That is why when i run this example the OneToOne relation gives error as
java.sql.SQLException: Conversion failed when converting the varchar to data type int.
because code is string value.
Is there any way to implement this scenario in Spring Mvc boot application?
Note: In sql server this query can do desired work.
SELECT * FROM STUDENT as e left join VLE_LOOKUP_DATA as di on e.DEPARTMENT_ID=di.CODE
JPA is designed to support wide range of DBMS ( database server ) so it just support SQL standard specification.
In your current case, compare equals between 2 fields is not supported by SQL spec ( may be just supported by sql server only ) so JPA raise this error. So I think instead of using relational mapping, to get the Lookup_data you can do normal JPQL or native query.
I am using: Spring 4, Hibernate 4, SQL Server 2008
I know how to do it with SQL Server 2008 from this question response How do I create a unique constraint that also allows nulls?
But since I don't generate any manual SQL code during the creation of the table, is it possible to generate a "where clause" in my constraint through Hibernate annotations in my Entity class?
My DDL is created from scratch with the java entity definition as follows:
#Entity
#Table(name="Neighborhood",
uniqueConstraints = {#UniqueConstraint(columnNames = {"codecnbv","zipcode"})})
#JsonSerialize(include = JsonSerialize.Inclusion.NON_EMPTY)
public class Neighborhood implements Serializable {
private String id;
private String codecnbv;
private String zipcode;
#Id
#Column(name="id", nullable=false, unique=true, length=2)
public String getId() {
return this.id;
}
#Column(name="codecnbv", nullable=true, length=12) //explicitly nullable
public String getCodecnbv() {
return codecnbv;
}
#Column(name="zipcode", nullable=true, length=5) //explicitly nullable
public String getZipcode() {
return zipcode;
}
}
However, as soon as I add data and try to enter a second record with NULL in column codecnbv and/or zipcode, I receive an exception that says I've violated the unique constraint.
The requirement I have says that I must allow multiple null values, and when the value is not null, then I should have unique values i.e.
For zipcode column
56000 --ok
NULL --ok
34089 --ok
NULL --ok
34089 --Not allowed
34567 --ok
It is not an issue of Hibernate but of SQL Server, which considers NULL a value and does not allow a second NULL value. Wicked, I know.
Some links:
How do I create a unique constraint that also allows nulls?
http://sqlmag.com/database-development/multiple-nulls-unique-constraints
I'm using Hibernate with a SQLite database. I have the following class :
#Entity
#Inheritance(strategy=InheritanceType.JOINED)
public abstract class Authority {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private int idAuthority;
(...)
I then have a class Author, that extends Authority and add 4 or 5 fields.
When I try to save an Author object, Hibernate generates the following request :
Hibernate: insert into Authority values ( )
And sqlite doesn't like that.
If I add a dummy String field, like "private String test" and set this property in the constructor, everything works fine.
I'm quite new to hibernate, so I'm not sure how to proceed. Do you have any idea ?
Edit : As requested, the mapping of the Author class :
#Entity
#Table(name="Authors")
#PrimaryKeyJoinColumn(name="idAuthority")
public class Author extends Authority {
#Column(name = "firstName")
protected String firstName;
#Column(name = "lastName")
protected String lastName;
#Column(name = "alias")
protected String alias;
(...)
}
Edit : As requested (bis), the insert code :
public void save(Object data) {
currentSession.saveOrUpdate(data);
}
Nothing fancy...
And to give you more possible leads, here is the database schema :
create table Authority (idAuthority integer, primary key (idAuthority))
create table Authors (alias varchar, firstName varchar,
lastName varchar, idAuthority bigint not null, primary key (idAuthority))
N.B. : in SQLite, an integer that is primary key is automatically set to AUTO-INCREMENT.
The Exception raised is this one :
java.sql.SQLException: near ")": syntax error
The request should be more like : insert into Authority values (NULL) to let SQLite do its auto-increment, not this weird "insert into Authority values ()".
Edit : This is definetely a problem with the SqlLite for Hibernate package. I just tried with Hsqldb, and it gives me a proper query :
insert into Authority (idAuthority) values (default)
(Then it fails too, but for very different reasons :p ).
I'm not sure there is a solution to this problem... other than using a different DB.
If you use InheritanceType.JOINED your table associated with class Authority must contain column associated with idAuthority and your table associated with class Author must contain column associated with idAuthority that is a foreign key to the primary identifier in table which presents Authority. It's required for table relations accociation
Try Overriding the ID.
#Entity
#Table(name="Authors")
#PrimaryKeyJoinColumn(name="idAuthority")
#AttributeOverride(name="idAuthority", column=#Column(name="id"))
public class Author extends Authority {
#Column(name = "firstName")
protected String firstName;
#Column(name = "lastName")
protected String lastName;
#Column(name = "alias")
protected String alias;
(...)
}