spring.jpa.hibernate.ddl-auto=update property alters the foreign key every time - spring

I am using spring.jpa.hibernate.ddl-auto=update property to update the schema.
As per my understanding if we do changes in the entity then table schema gets updated.
But on spring boot app startup every time alter command gets executed for the foreign key.
Following is the entity.
#Entity
#Table(name = "feedback")
#Data
public class Feedback implements Serializable {
private static final long serialVersionUID = -6420805626682233375L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "study_id")
#JsonIgnore
private Study study;
#ManyToOne(fetch= FetchType.EAGER)
#JoinColumn(name="user_id", nullable = false)
private User user;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "feedback_date", nullable = false)
private Date feedbackDate;
#Size(max = 1000)
#Column(name = "feedback", length = 1000)
private String feedback;
}
In entity you can see I have following two property for that foreign key gets created on spring boot app starts first time:
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "study_id")
#JsonIgnore
private Study study;
#ManyToOne(fetch= FetchType.EAGER)
#JoinColumn(name="user_id", nullable = false)
private User user;
So when I am restarting the app or saving the code every time foreign key constraints gets altered even if I am not changing that relationship(property).
2018-12-05 18:44:12.027 INFO 22736 --- [ restartedMain] c.d.smartviewer.SmartViewerApplication : Starting SmartViewerApplication on LAPTOP-F95LLCU3 with PID 22736 (D:\Sagar_\SVN\SmartViewer\target\classes started by ASUS in D:\Sagar_\SVN\SmartViewer)
2018-12-05 18:44:12.027 DEBUG 22736 --- [ restartedMain] c.d.smartviewer.SmartViewerApplication : Running with Spring Boot v2.0.6.RELEASE, Spring v5.0.10.RELEASE
2018-12-05 18:44:12.027 INFO 22736 --- [ restartedMain] c.d.smartviewer.SmartViewerApplication : No active profile set, falling back to default profiles: default
2018-12-05 18:44:13.356 INFO 22736 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1329 ms
Hibernate: alter table annotation add constraint FK7hwy1g5myfk7grmm2j7faqggd foreign key (parent_id) references annotation (id)
Hibernate: alter table feedback add constraint FKfxt8nk3jikofi3x40bsjd00vt foreign key (study_id) references study (id)
Hibernate: alter table feedback add constraint FK7k33yw505d347mw3avr93akao foreign key (user_id) references user (id)
Hibernate: alter table hospital add constraint FK3922fhj7qnyc3bw5x8xl6m6xc foreign key (contact_1) references contact (id)
So what should I change to not execute alter command for the foreign key if I do not change the foreign key entity property?

Constraints are part of a database schema definition.
Constraints are the rules enforced on the data columns of a table. These are used to limit the type of data that can go into a table. This ensures the accuracy and reliability of the data in the database. Constraints could be either on a column level or a table level. The column level constraints are applied only to one column, whereas the table level constraints are applied to the whole table.
kinds of constraints are:
NOT NULL− Ensures that a column cannot have NULL value.
DEFAULT - Provides a default value for a column when none is specified.
UNIQUE - Ensures that all values in a column are different.
PRIMARY KEY - Uniquely identifies each row/record in a database table.
FOREIGN KEY - Uniquely identifies a row/record in any of the given database table.
CHECK CONSTRAINT - The CHECK constraint ensures that all the values in a column satisfies certain conditions.
INDEX - Used to create and retrieve data from the database very quickly.
Q : Is this constraint in hibernate optional or cancel to update ?
A : No. it is not optional, it is needed for relational entity.
You can also define this constraint in your DB to changes while run time if necessary but be careful not recommended.
I think this is a bug for hibernate to alter every time base on this below link (same problem):
https://discourse.hibernate.org/t/manytoone-alter-table-query-is-generating-every-time-when-inserting-a-value/1162/6

Related

Spring Data JDBC aggregate ID in child objects

I was playing with Spring-Data-JDBC and encountered 2 issues. I have following entities with 1:N relationship.
------
DROP TABLE IF EXISTS product;
CREATE TABLE product (
product_id int AUTO_INCREMENT PRIMARY KEY,
name varchar(250) not null,
description varchar(512) not null
);
DROP TABLE IF EXISTS product_line;
CREATE TABLE product_line (
product_id int constraint fk_product_line_product references product(product_id),
label varchar(250) not null
);
----------
#Data
#Builder
public class Product {
#Id
private Long productId;
private String name;
private String description;
#Singular
#MappedCollection(idColumn = "product_id", keyColumn = "product_id")
private Set<ProductLine> lines;
}
#Data
#Builder
public class ProductLine {
private Long productId;
private String label;
}
Problem 1: Following test case fails because I was expecting to have the productId populated in the ProductLine object but it is not. Is this the expected behavior of Spring Data JDBC?
#SpringBootTest
class SpringDataJdbcApplicationTests {
#Autowired
private ProductRepository productRepository;
#Test
void saveTest() {
Product product = Product.builder()
.name("Product-1")
.description("Description")
.line(ProductLine
.builder()
.label("Line-label")
.build())
.build();
this.productRepository.save(product);
assertThat(product.getProductId()).isNotNull();
assertThat(product.getLines()).isNotNull().isNotEmpty().hasSize(1);
assertThat(product.getLines().stream().findFirst()).isPresent();
assertThat(product.getLines().stream().findFirst().get().getProductId()).isNotNull().isEqualTo(product.getProductId()); // -----> Fails here.
}
}
Problem 2: If I change Set<ProductLine> to List<ProductLine>, it fails due to JdbcSQLIntegrityConstraintViolationException, which means the product id set to 0 as seen in the log snippet below.
2022-09-10 22:33:12.393 DEBUG 18460 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL statement [INSERT INTO "PRODUCT_LINE" ("LABEL", "PRODUCT_ID") VALUES (?, ?)]
2022-09-10 22:33:12.393 TRACE 18460 --- [ main] o.s.jdbc.core.StatementCreatorUtils : Setting SQL statement parameter value: column index 1, parameter value [Line-label], value class [java.lang.String], SQL type 12
2022-09-10 22:33:12.393 TRACE 18460 --- [ main] o.s.jdbc.core.StatementCreatorUtils : Setting SQL statement parameter value: column index 2, parameter value [0], value class [java.lang.Integer], SQL type 4
Following test case fails because I was expecting to have the productId populated in the ProductLine object but it is not. Is this the expected behavior of Spring Data JDBC?
Yes, if you want a productId you have to (and can easily) populate it yourself using plain Java code.
But you really shouldn't need the productId in the first place since if you follow Domain Driven Design, you will access a ProductLine exclusively from a Product which already has the id at hand.
The article https://spring.io/blog/2021/09/22/spring-data-jdbc-how-do-i-make-bidirectional-relationships might be helpful.
If I change Set<ProductLine> to List<ProductLine>, it fails due to JdbcSQLIntegrityConstraintViolationException, which means the product id set to 0 as seen in the log snippet below.
You have two problems here:
You already have two sources for the product_id field: The relation from the aggregate root and the simple field, which may cause problems.
You mapped both the back reference to the aggregate root idColumn and the index of the list keyColumn to the same database column. Together with the simple field from above these are three values all mapped to the same column. Not good.
The value that seems to win is the list index, resulting in the exception.
In order to fix that, create an additional column in the product_line table and map the list index to it.

How to establish foreign key relationship with a non entity table in the database using Spring data JPA?

My spring boot project uses an existing database, I have a new model entity/table in my project that must have a foreign key constraint with an existing table in the database.
I've tried to find solution online but all the answers are for the case where both the tables are present as entities in that project and using some #ManyToOne, #OneToMany annotations.
I can't define those annotations because I don't have the reference table as an entity or model in my project.
Let's say I have class like:
#Entity(name = "user")
public class User {
#Id
#GeneratedValue
private long userId;
private long departmentId;
I want to put a foreign key contraint on the departmentId column to reference to id column of the existing department table that isn't defined as a model or entity in my project.
Thanks
Just do it as normal
example
#Column(name = "department_id")
private Department departmentId;
You can later access it Department.departmentId. Hope this helps.
Try it like this
#ManyToOne
#JoinColumn(name="(column name of current entity)", referencedColumnName="(column name in target entity)")
private Department departmentId;
you can skip the referencedColumnName if the column name is same in both the entities

Spring Data JPA : not persisting parent relation column mapping

Currently I am following this URL & implemented the similar kind of code at my end.
But it gives an error at my end something likewise,
null value in column "file_id" violates not-null constraint
Here, category_id is one of my parent_entities primary key.
Following lines where parent entity I am passing properly & checked through Debug,
EntityManager entityManager = BeanUtil.getBean(EntityManager.class);
entityManager.persist(new FileHistory(target, action));
UPDATE -
Here, instead of the following config,
#ManyToOne
#JoinColumn(name = "file_id", foreignKey = #ForeignKey(name = "FK_file_history_file"))
I've used,
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "file_id")
Also, I used #PostPersist instead of #PrePersist these are the changes only I did against this article.

Spring JPA one to many

I have two entities :
#Entity
#Table(name="Registration")
public class Registration{
#Id
private UUID uuid;
#OneToMany(cascade = {CascadeType.PERSIST, CascadeType.REMOVE, CascadeType.MERGE}, fetch = FetchType.LAZY)
#JoinColumn(name="registration", nullable = false)
private List<Payment> payment;
}
#Entity
#Table(name="Payment")
public class Payment {
#Id
private UUID uuid;
/*#ManyToOne(targetEntity = Registration.class) <-- MappingException: Repeated column in mapping for entity
private Registration registration;*/
}
This entities create two tables :
TABLE `registration` (
`uuid` binary(16) NOT NULL,
PRIMARY KEY (`uuid`))
TABLE `payment` (
`uuid` binary(16) NOT NULL,
`registration` binary(16) NOT NULL,
PRIMARY KEY (`uuid`),
CONSTRAINT `FK_jgemihcy9uethvoe3l7mx2bih` FOREIGN KEY (`registration`) REFERENCES `registration` (`uuid`))
I'm using Rest Service. I can access to
registration.payment
but not
payment.registration
why ? I need a relation oneToMany bidirectionnal ?
Yes, you need to add the payment.registration #ManyToOne relationship if you use it in your code.
Take into account that JPA allows you to map a SQL database model to an object oriented one. Once you have the mapping between your objects and your database, you always work at the object level. That's why, although you have the relationship in the database, your Payment object doesn't know anything about it unless you map it to an attribute.
Of course it applies when you are using you data model objects or performing JPQL or Criteria queries. If you use native queries you have access to the database model as it is.

Unable to see generated tables generated by hibernate schema export (H2 database)

I am trying to get a small app going using Spring Boot (v1.1.1.RELEASE), and H2 database. In the logging i see that the ddl is correctly generated but it i just cannot find the tables inside the H2 database.
I manually copied the ddl into a db visualizer and the sql is ok. I have no clue what i am missing here. When executing code the JPA persistence layer seems to store the data correctly as i get generated ID's back etc.. I was thinking that i made a mistake in the jdbc url, but they all point to the same file based H2 database. But this database just seems to hold no data.
The JPA object
#Entity
#Table(name = "rawdata", schema = "PUBLIC")
public class RawData {
#Id
#GeneratedValue
private Long id;
#Lob
#Column(name = "payload", nullable = false)
private String payload;
// getters and setters omitted
}
The JPARepository
#Repository
public interface RawDataRepository extends JpaRepository<RawData, Long> {
}
Application properties
spring.datasource.url=jdbc:h2:file:/home/username/dev-db
spring.datasource.driverClassName=org.h2.Driver
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.show-sql=true
Logging info
org.hibernate.tool.hbm2ddl.SchemaExport : HHH000227: Running hbm2ddl schema export
Hibernate: drop table PUBLIC.rawdata if exists
Hibernate: create table PUBLIC.rawdata (id bigint generated by default as identity, payload clob not null, primary key (id))
org.hibernate.tool.hbm2ddl.SchemaExport : HHH000230: Schema export complete
Test code
#Autowired
private RawDataRepository repository;
repository.saveAndFlush(new RawData("test"));
System.out.println(repository.count());
So saving a JPA object actually seems to persist the object (the count increases etc) but the data and table structure do not appear in the database. I see that the modified date changes of the database when persisting an object but i seem unable to view the data with for example squirrel/dbvisualizer etc.. Any hints or tips?
The problem is that when the application is shutdown, Hibernate will drop the entire schema, because you have configured spring.jpa.hibernate.ddl-auto=create-drop.
If you change your configuration to spring.jpa.hibernate.ddl-auto=create the schema will not be dropped at the end of the session and you will be able to see the tables that where created along with any data you inserted

Resources