Update column name for existing Entity class using Hibernate Annotation - java

I have one column in my Entity Class like :
#Column(name = "createdBy", nullable = false)
private String createdBy;
Later i need to update column name.
Is there any way to update the column name using hibernate annotation which will not generate new column.

Nope. You should use annotation and SQL script to modify table.

Related

Hibernate + JPA does not find the column for an #ElementCollection table

I am trying to add an #ElementCollection but the column is not found after the setup, so I constantly receive an error. I use Spring + flyway for the set up. Everything happens in the public schema
So here is my big object:
#Entity
#Table(name = "my_big_table")
MyBigObject{
#Id
#Column(name=COL_ID)
#GeneratedValue(generator="gen_name")
#GenericGenerator(
name = "gen_name",
strategy = "seq_name"
)
#AttributeAccessor(CommonConstants.HIBERNATE_ACCESS_PROPERTY)
private long id;
...
...
#ElementCollection(fetch = FetchType.EAGER)
#CollectionTable(
name = "my_small_table",
joinColumns = #JoinColumn(name = "big_object_id")
)
private List<MySmallObject> mySmallObjects;
}
Here is my embedded object:
#Embeddable
public class MySmallObject {
#Column(name = "small_object_type")
private String smallObjectType;
}
Then besides the existing my_big_table table I add my_small_table using flyway
create table if not exists my_small_table
(
big_object_id bigint not null,
small_object_type varchar(64) not null
);
alter table my_small_table
add constraint FK_my_small_table
foreign key (big_object_id)
references my_big_table (id);
After this the my_small_table is successfully created but any instance of MyBigObject cannot be found because it looks for a column in the my_small_table that does not exist. As you can see it does not understand that the column name should use an underscore.
Big error trace ands with the following message:
Caused by: org.postgresql.util.PSQLException: ERROR: column mysmalltab0_.smallobjecttype does
not exist
09:17:24.994 INFO - STDOUT: Hint: Perhaps you meant to reference the column "mysmalltab0_.smallobjecttype".
Do you know what I could forget? Could lombock annotations that I also use for both classes spoil the picture?
As it's stated in the documentation:
By default, the placement of the #Id annotation gives the default access strategy. When placed on a field, Hibernate will assume field-based access. When placed on the identifier getter, Hibernate will use property-based access.
But the usage of the #AttributeAccessor leads to the changing access strategy for the field that hold #Id and as result your #Column(name = "small_object_type") annotation just was ignored. You can try to put it on the appropriate getter and it should work. But it's considered a good practiсe not to mix up access strategies for the entity fields.

The default entity from enum

I have property in Enum:
#Basic
#Column(name = "payment_status", columnDefinition = "varchar(32) default 'ENTERED'", nullable = false)
#Enumerated(EnumType.STRING)
private PaymentStatus paymentStatus;
I want to get the default value for a field from enum
I have error:
org.hibernate.PropertyValueException: not-null property references a null or transient value
The field cannot be null
The error is when I want to create an object and save in the database without entering this field (PaymentStatus)
EDIT:
#Basic
#ColumnDefault(value = "ENTERED")
#Column(name = "payment_status", nullable = false)
#Enumerated(EnumType.STRING)
private PaymentStatus paymentStatus = PaymentStatus.ENTERED;
Why is it not working?
default 'ENTERED' tells the database to use value 'ENTERED' if the column is not included in the INSERT statement. Since the column is in the class, JPA will always include it in the INSERT statement.
To make JPA fill in the default value, simply assign it with an initializer, so it has that value until replaced by you (calling setter method), or replaced from database (when reading from there).
private PaymentStatus paymentStatus = PaymentStatus.ENTERED;
If you have defined a default in the database and if you want to leave it to the database to set the default value then you need to prevent a null being inserted to that column in the SQL insert statement
You would then need to look at what your JPA provider offers in that area. In Hibernate, for example, you would simply annotate your Entity with #DynamicInsert:
https://docs.jboss.org/hibernate/orm/5.2/javadocs/org/hibernate/annotations/DynamicInsert.html
For inserting, should this entity use dynamic sql generation where
only non-null columns get referenced in the prepared sql statement?
It should be noted that defining a default in the JPA annotations (as you have done) only has any effect on DDL generation i.e. if you are having your JPA provider generate or update your schema and has to effect on any insert or update operations.

Hibernate renames some columns at start with Spring Boot 1.4

I'm having some problems with my PostgreSQL database columns on some tables.
If I declare a column of String with a name like a_column_name Hibernate accepts the column of the table with the name a_column_name.
But my problem comes when I declare the column type to Integer or BigDecimal. At start, Hibernate creates a new column of type int4 or numeric(19, 2) with a name like acolumnname with NULL's.
Hibernate: alter table t_myTable add column acolumnname int4
or
Hibernate: alter table t_myTable add column acolumnname numeric(19, 2)
I've tried to set the name-strategy on the config file of Spring boot:
jpa:
show-sql: true
hibernate:
ddl-auto: update
properties:
hibernate.cache.use_second_level_cache: false
hibernate.cache.use_query_cache: false
hibernate.generate_statistics: true
naming.physical-strategy: PhysicalNamingStrategyStandardImpl
But with no result...
So my question is why Hibernate accepts the column name when it's of String type but doesn't like it when it's Integer or BigDecimal.
Regards.
---- Update 1 ----
After search the Entity to post here the code as Veselin Davidov asked, I've noticed that some columns are accepted while others not.
The entities are created from a company framework that parses a JSON with the DB structure (tables, fields, type of fields...) and generates the JAVA entity class. So after see the answer from SAM I've changed the code of the Entity template to add a #Column(name = "your_column_name"). Now, when Hibernate starts, it doesn't add the columns with the wrong names and uses the DB columns.
if your Hibernate entity class is like the following:
#Entity
public class Registration{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#Column
#Basic
private String name;
// getters and setters
}
then your registration table will have fields named with "id" and "name" as you have used auto-ddl=update. To avoid that you can specify the column names with #Column(name = "your_column_name") like below:
#Table(name = "registration")
#Entity
public class Registration{
#Id
#Column(name = "r_id")
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#Basic
#Column(name = "r_name")
private String name;
// getters and setters
}
If you are using Intellij IDEA then the IDE can generate the required Entity class.
You can go to your persistence tab -> right-click on your project name -> Generate Persistence Mapping -> By Database Schema. Then select the tables whose Entity you want to generate. Voila everything comes with ease.
Now coming to your problem, in your Entity class if you set some filed with Integer type then it will update your table to int4 and with allow null. The BigDecimal is also same numeric(10,2) with allow null. To avoid allow null in your database use primitive type int and double.

Spring boot JPA: remove column on entity change

I am try to create table in MySQL database from java class using spring-boot-starter-data-jpa. It work pretty well except when I change/remove column name in java class. Here an example:
I have a class call "Staff" with 2 fields: id, name
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private int id;
#Column(name = "name", length = 15)
private String name;
public Staff() {
}
// some setter and getter here
When I run my project, a "Staff" table generated exactly as I want with 2 columns: id, name. The problem is if I split "name" into "firstname" and "lastname" like this:
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private int id;
#Column(name = "firstname", length = 15)
private String firstname;
#Column(name = "lastname", length = 15)
private String lastname;
public Staff() {
}
//some getter and setter here
The "Staff" table now contain 4 columns (id, name, firstname, lastname) instead of 3. Then I need to remove the "name" column myself. Is there anyway to get rid of it automatically?
Looks like you use :
spring.jpa.properties.hibernate.ddl-auto=update
78.1 Initialize a database using JPA
spring.jpa.generate-ddl (boolean) switches the feature on and off and
is vendor independent. spring.jpa.hibernate.ddl-auto (enum) is a
Hibernate feature that controls the behavior in a more fine-grained
way. See below for more detail.
You can set spring.jpa.hibernate.ddl-auto explicitly and the standard
Hibernate property values are none, validate, update, create,
create-drop.
as you can see there is nothing new (different from hibernate)
ddl-auto=update - generate changes but it doen't drop not mapped columns .
For example you can have a table with 10 columns and mapping only for 3 of them , in this case auto mode might drop them but for hibernate / jpa full mapping table-entity in not mandatory. Here is jira ticket Alter and drop columns with hbm2ddl.auto=update created Nov 2011 and now status is 'not fixed'.
If you update db often (your domain model is changed) , you can use ddl/dml tools like liquibase , flywaydb. You describe db changes in xml file , and execute tool , all changes will be apply automatically (with auto control what already modifyed before and what should be modifed now).
Just recommendation :
Better use ddl tools if you don't want to guess why something is droped in production. hibernate.ddl-auto maily used for development , not for production. In production you can use none or validate - as they are safe.

checking uniq constraints without using primary key

I am using hibernate only with Annotations. My table looks something like this:
#Entity
#Table(name = "NetworkType",
uniqueConstraints = {#UniqueConstraint(columnNames = {"network_id", "type"})})
public class NetworkType implements Serializable {
#Id
private long id;
#Column(name = "network_id", nullable = false)
private long networkId;
#Column(name = "type", nullable = false)
private String type;
...
Currently when I write the same NetworkType twice, it throws an exception due to the UniqueConstraint (which is expected).
My thoughts are to just read the item first before checking. The problem is, my primary key is the Id, which I need because other tables references this table.
What's the best way to query for item for the "network_id" and "type" to verify the combination doesn't already exist?
I know I can do this with a Query manually, but is there a more Hibernate-y way of doing it?
In general, what's the proper way to "get" an object without using the PK? Are Criteria or Query the best way?
#UniqueConstraint is mainly used by database schema generation tools to create the data base schema. If used, they will generate the table with the columns mentioned in the #UniqueConstraint having unique constraint defined.
#UniqueConstraint doesn't have any impact/usage during data manipulation.
If you wish to achieve unique constraint behavior on network_id and type columns and your schema is already created, update your database schema to add the unique constraint on network_id and type columns. as below:
ALTER TABLE NetworkType
ADD CONSTRAINT uc_network_id_type UNIQUE (network_id, type)
Hope this helps!

Categories