How to get Hibernate to ignore table columns not in entity? - java

I'm using Java with Spring MVC and Hibernate. I have a bunch of entities and everything works fine. If, however, I add a column to one of my database columns, my service will start crashing until I also update the relevant java entity class with the new column.
Is there a way to tell Hibernate to ignore database columns it doesn't recognize? If you want to have a field in your entity that's not in your DB table, you would use #Transient on the field. I want the inverse of that.
If this is not possible, how do Hibernate services get deployed when there's a database update that has to go along with it?

Hibernate will not "crash" after new columns were added to a table managed by Hibernate. Hibernate scheme validation goes only as far as verifying that the mapped columns can be stored in the database, but will not look for unmapped columns in the database.
What is likely causing your problem is a new NOT-null field. Adding such a field will make it impossible for Hibernate to persist anything into that table since it is oblivious to the existence of this field and will not provide it at insertion-time. Solutions to this problem are:
Providing DEFAULT in the alter table operation for clients that do not use this field
Not marking the field not-null and performing nullability checks in another layer
Using pre-insert triggers to populate the empty fields
Alternatively you can even add the new field first, deploy your new version of your application, then mark the new field as not-null.

Related

Spring Data JPA creates two tables after renaming entity

I'm using Spring Boot 2.6.4 and Java 17. And I previously had an Entity called BlogPostComment but recently decided that just Comment is more concise. I don't have a data.sql file to explicitly create tables and let Hibernate handle all the database operations for me. So I'm expecting that the table previously named blog_post_comment would be renamed as comment. However, when I rerun my application after renaming the entity, Hibernate creates two tables blog_post_comment and comment instead of just the latter.
Before renaming:
#Entity
public class BlogPostComment { ... }
After renaming:
#Entity
public class Comment { ... }
I've tried adding #Table(name = "comment") annotation to this entity, but Hibernate created the table with the old name all the same. And I've also tried invalidating IntelliJ IDEA caches, still did not solve this problem. Please help me identify the cause of this error, thank you.
It is possible that your hibernate.hbm2ddl.auto property in application.properties is set to none . What none does is that no action is performed. The schema will not be generated. Hence your changes will appear as a new table in your database. What you should do then is to set the property to update and then run the application. What update does is that the database schema will be updated by comparing the existing database schema with the entity mappings.
PS: If no property is defined, the default property is none. You should add the property and set to update
I strongly doubt that Hibernate creates a blog_post_comment table after you renamed the entity. I suspect this is just still around from the previous run.
Hibernate (or any other JPA implementation) does not know about you renaming the entity. It has no knowledge what so ever about the entities present during the last start of the application. Therefore it doesn't know that there is a relationship between the existing blog_post_comment table in the database and the not yet present comment table it is about to create.
When Hibernate "updates" a schema it checks if a required table already exists and if so it modifies it to match what is required by the entities. But even then it won't rename columns, it would just create new ones.
In generally you should use Hibernates schema creation feature only during development and never for actually deploying a schema into production or even worse, updating a schema in production. For this you should use specialised tools like Flyway or Liquibase which exist for exactly this purpose.

What is the convenient schema update strategy to add #NotNull property to existing domain model in the context of hibernate?

I currently develop a small Java application with help of Spring Boot and Hibernate. As my application evolves, so does the domain model too. Last time I'm facing frequent updates of my domain model - new columns are added to existing tables. This new column addition happens not manually, but automatically via configured hibernate.ddl-auto=update property, as soon as I introduce new class variable (field) in my entity class.
The problems appear as soon as I add a new #NotNull annotation at the same time as I introduce new field, what is not surprising: old table entries could not have valid data in the new column without further action, therefore the whole update could result in corrupting database if it succeeds. Especially then, if hibernate first updates the table (by setting #NotNull constraint on the column), but then finds out that a lot of data in this column is invalid (null). Because of the hibernate.ddl-auto=update the corrupted column can not be restored with simple rollback of #NotNull property on the newly introduced field (i.e. if I comment this annotation out and start the application one more time). This is the reason why I am enforced to drop the whole table with the corrupted data in such situation, what is definitely not the way to do things properly, especially outside of the development environment.
Therefore my question: is there a way to update the existing domain model, such that the constraint #NotNull will not introduce such problems on newly created fields? What are the best practices for this sort of schema updates, especially if I want to avoid manually updating the whole database schema and want further rely on the hibernate schema creation?
If you want to set a default value for ALL rows you can set a default value with the #ColumnDefault annotation
If that's not fitting your requirements you might have just discovered one of the reasons why it's actually best practice NOT to rely on schema updater for production purposes at all, see official hibernate documentation - 26. Performance Tuning and Best Practices

Why does Spring-data-jdbc not save my Car object?

I'm playing around with spring-data-jdbc and discovered a problem, with I can't solve using Google.
No matter what I try to do, I just can't push a trivial object into the database (Bean1.java:25):
carRepository.save(new Car(2L, "BMW", "5"));
Both, without one and with a TransactionManager +#Transactional the database (apparently) does not commit the record.
The code is based on a Postgres database, but you might also simply use a H2 below and get the same result.
Here is the (minimalistic) source code:
https://github.com/bitmagier/spring-data-jdbc-sandbox/tree/stackoverflow-question
Can somebody tell me, why the car is not inserted into the database?
This is not related to transactions not working.
Instead, it's about Spring Data JDBC considering your instance an existing instance that needs updating (instead of inserting).
You can verify this is the problem by activating logging for org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate. You should see an update but no insert.
By default, Spring Data JDBC considers an entity as new when it has an id of an object type and a value of null or of a primitive type (e.g. int or long) and a value of 0.
If your entity has an attribute with #Version annotation that attribute will be used to determine if the instance is a new one.
You have the following options in order to make it work:
Set the id to null and configure your database schema so that it will automatically create a new value on insert. After the save your entity instance will contain the generated value from the database.
Note: Spring Data JDBC will set the id even if it is final in your entity.
Leave the id null and set it in a Before-Convert listener to the desired value.
Let your entity implement Persistable. This allows you to control when an entity is considered new. You'll probably need a listener as well so you can let the entity know it is not new any longer.
Beginning with version 1.1 of Spring Data JDBC you'll also be able to use a JdbcAggregateTemplate to do a direct insert, without inspecting the id, see https://jira.spring.io/browse/DATAJDBC-282. Of course, you can do that in a custom method of your repository, as is done in this example: https://github.com/spring-projects/spring-data-examples/pull/441

How to alter databases tables at run time using JPA?

I am creating CRUD application for customer . and he asked me to allow him to create new Fields in a form (database columns) without restarting the application server. which JPA implementation should I use (hibernate , eclipselink ,openjpa)
to accomplish this task and how it will be done?
Please don't change the database schema at runtime.
Assuming, you would add a column to a table. Then you have to add a field in your entity class, too. And the mapping. So you not only have to change a Java class at runtime, at next application start, you must add this field again. No JPA implementation can do that.
Of course, you can use plain JDBC. And instead of entity classes with concrete fields you can use something like a map for your dynamic fields. But you should adapt all your SQL queries according to the presence of dynamic fields. So you need a way to store the information, which dynamic fields are already created. You can do this with another table or use the table meta information. Additionally you have to manage user defined field names. E.g you should avoid SQL keywords, there is a maximum field name length, etc.
Or you can step back and rethink your approach. You have a requirement: Static given fields in a form and the possibility to create dynamic fields.
Why not adapt your data model to that requirement? A data model which is able to handle dynamic form fields. Such flexible datamodel wouldn't need dynamic SQL table field creation. (And JPA can handle that, too.)
The simplest example would be a table with two columns. One for the field name and one for the value (as string). Maybe a third one to identify the type.
Another alternative would be to use a NoSQL database system like a key value store or a document oriented database.

Hibernate forward Engineering

I want to implement a simple application Hibernate forward engineering concept. Where If I make any changes to Hibernate Entities then Hibernate should automatically make specific changes to the database columns.
For example:
If I add a new field in Hibernate Entity (POJO), then a new column should be added to the DB table. (This should happen when I restart tomcat).
Is this possible?
You can do this using hibernate configuration property hibernate.hbm2ddl.auto. set this property value to update to reflect changes from POJO to database. Refer this link for more information.

Categories