Cannot get many to many relationship in spring bootstrap - spring-boot

I have a very simple many to many scenario: One ORDER has many PRODUCT, and each product can belong to many orders.
order :
#Entity
#Table(name = "ORDER")
public class OrderEntity {
#Id
#Column(name="ORDER_ID")
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#Column(name="ORDER_NAME")
private String name;
#Column(name="ORDER_DATE")
private Date date;
#ManyToMany
private List<ProductEntity> selectedProducts = new ArrayList<>();
product:
#Entity
#Table(name = "PRODUCT")
public class ProductEntity {
#Id
#Column(name="PRODUCT_ID")
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#Column(name="PRODUCT_NAME")
private String name;
#Column(name="PRODUCT_PRICE")
private BigDecimal price;
#ManyToMany
private List<OrderEntity> orders = new ArrayList<>();
(removed getters and setters and constructors for brevity)
However when I startup bootstrap then I get a whole host of errors :
Error executing DDL "drop table order if exists" via JDBC Statement
Syntax error in SQL statement "DROP TABLE ORDER[*] IF EXISTS "; expected "identifier"; SQL statement:
Error executing DDL "create table order (order_id bigint not null, order_date timestamp, order_name varchar(255), primary key (order_id))" via JDBC Statement
Syntax error in SQL statement "CREATE TABLE ORDER[*] (ORDER_ID BIGINT NOT NULL, ORDER_DATE TIMESTAMP, ORDER_NAME VARCHAR(255), PRIMARY KEY (ORDER_ID)) "; expected "identifier"; SQL statement:
create table order (order_id bigint not null, order_date timestamp, order_name varchar(255), primary key (order_id)) [42001-199]
Error executing DDL "alter table order_selected_products add constraint FKrbll8c9ubhjqangdfw2sgkurw foreign key (order_entity_order_id) references order" via JDBC Statement
Syntax error in SQL statement "ALTER TABLE ORDER_SELECTED_PRODUCTS ADD CONSTRAINT FKRBLL8C9UBHJQANGDFW2SGKURW FOREIGN KEY (ORDER_ENTITY_ORDER_ID) REFERENCES ORDER[*] "; expected "identifier"; SQL statement:
alter table order_selected_products add constraint FKrbll8c9ubhjqangdfw2sgkurw foreign key (order_entity_order_id) references order [42001-199]
Error executing DDL "alter table product_orders add constraint FK9pa3r9u6x44jjxrkkhdvhu23k foreign key (orders_order_id) references order" via JDBC Statement
Syntax error in SQL statement "ALTER TABLE PRODUCT_ORDERS ADD CONSTRAINT FK9PA3R9U6X44JJXRKKHDVHU23K FOREIGN KEY (ORDERS_ORDER_ID) REFERENCES ORDER[*] "; expected "identifier"; SQL statement:
alter table product_orders add constraint FK9pa3r9u6x44jjxrkkhdvhu23k foreign key (orders_order_id) references order [42001-199]
I'm not sure why there are these syntax errors. Is this some kind of SQL dialect issue?

ORDER is a very common reserved keyword and that is the root cause of the errors you see.
Change your table name to something else, such as ORDERS, or if you really want to use that name you can try escaping it:
#Entity
#Table(name = "\"ORDERS\"")
public class OrderEntity {
....
}
List of reserved keywords for some common databases:
https://docs.oracle.com/cd/B28359_01/appdev.111/b31231/appb.htm#BABDFFBA
https://learn.microsoft.com/en-us/sql/t-sql/language-elements/reserved-keywords-transact-sql?view=sql-server-2017
https://www.postgresql.org/docs/current/sql-keywords-appendix.html
https://dev.mysql.com/doc/refman/8.0/en/keywords.html

Related

Strange validation conflict in Spring JPA TableGenerator

I have a legacy database with composite primary key in table project. (BaseEntity contains common properties for lastModifiedDate and lastModifiedBy)
#Entity
#IdClass(ProjectPk.class)
public class Project extends BaseEntity {
#Id
#GeneratedValue(strategy=GenerationType.TABLE, generator="nextProjectId")
#TableGenerator(
name="nextProjectId",
table="projectId",
pkColumnName = "proj_Id",
pkColumnValue="proj_id"
)
private Long projId;
#Id
private int version;
//other properties, getters and setters omitted for clarity
}
PK class
public class ProjectPk implements java.io.Serializable {
private int projId;
private int version;
//both constructoirs, equals, hashcode, getters and setters omitted for clarity
}
I have flyway migration files to simulate production database.
drop table if exists project;
CREATE TABLE project
(
proj_id bigint,
version int,
-- other columns omitted for clarity
PRIMARY KEY (`proj_id`, `version`)
) ENGINE=InnoDB;
drop table if exists project_id;
CREATE TABLE project_id
(
proj_id bigint
) ENGINE=InnoDB;
flyway creates tables as ordered in migration file
Table: project_id
Columns:
proj_id bigint
...
Table: project
Columns:
proj_id bigint PK
version int PK
...
during maven build I'm getting validation error
Schema-validation: wrong column type encountered in column [proj_id] in table [project_id]; found [bigint (Types#BIGINT)], but expecting [varchar(255) (Types#VARCHAR)]
What I did wrong to make hibernate expect [varchar(255) (Types#VARCHAR)]?
This is SpringBoot project 2.6.6 with MySql database
I see the following problems with your code:
Type mismatch between Project.projId (Long type) and ProjectPk.projId (int type).
You use wrong table structure for the project_id table.
You can see a working example below.
Assuming that you have the following tables:
CREATE TABLE test_project
(
proj_id bigint,
version int,
title VARCHAR(50),
PRIMARY KEY (proj_id, version)
);
create table table_identifier (
table_name varchar(255) not null,
product_id bigint,
primary key (table_name)
);
insert into table_identifier values ('test_project', 20);
and the following mapping:
#Entity
#Table(name = "test_project")
#IdClass(ProjectPk.class)
public class Project {
#Id
#GeneratedValue(strategy = GenerationType.TABLE, generator = "nextProjectId")
#TableGenerator(
name="nextProjectId",
table="table_identifier",
pkColumnName = "table_name",
valueColumnName="product_id",
allocationSize = 5
)
#Column(name = "proj_id")
private Long projId;
#Id
private int version;
// other fields, getters, setters ...
}
you will be able to persist the entity like below:
Project project = new Project();
project.setVersion(1);
// ...
entityManager.persist(project);

Partitioning springboot postgres table

I've a springboot app where I need to implement db partitioning (by "range") for posts table based on posted_at attribute value.
Entity:
#Entity
public class Post {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(updatable = false, nullable = false)
private BigInteger id;
private String title;
private Date postedDate;
.....
}
Liquibase migration:
<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.0.xsd">
<changeSet id="00001" author="author">
<sql splitStatements="true">
CREATE TABLE posts (
id bigint primary key,
title varchar(200),
posted_at timestamp with time zone) PARTITION BY RANGE (posted_at)
</sql>
</changeSet>
When I run the above db migration, Postgres complains that I should add primary key also into the partition keys which I don't really want to. If I remove the primary key from the table, JPA will start throwing exception saying that I cannot have an entity without #Id field. How can this be resolved?
PS: I'm using plain sql inside Liquibase migration as liquibase has no direct support for db partitioning.

How to delete entity related to another entity

I have this entities:
Batch, Malt, Country - batch contains malts (#ManyToMany), malt came from some country (#ManyToOne).
Relations are as following:
Batch:
#JoinTable(name="batch_malt",
joinColumns = #JoinColumn(name="batch_id"),
inverseJoinColumns = #JoinColumn(name="malt_id"))
private Set<Malt> malts = new HashSet<>();
Malt:
#NotNull
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="country_id")
private Country country;
#ManyToMany(mappedBy="malts")
private Set<Batch> batches;
Country:
No mappinge since it is #ManyToOne from Malt.
Country Service:
#Override
public void deleteById(Long countryIdToDelete) {
Set<Malt> malts = maltRepository.findByCountry_id(countryIdToDelete);
if (malts != null) {
for (Malt tempMalt : malts) {
log.debug("Deleting country from malt number: " + tempMalt.getMaltName());
tempMalt.setCountry(null);
}
maltRepository.deleteById(countryIdToDelete);
}
}
I want to delete Country (I don't want to delete Malt - null shoul be instead)
When I'm trying do delete Country I get:
There was an unexpected error (type=Internal Server Error, status=500).
could not execute statement; SQL [n/a]; constraint ["FKM636T1NDS3GNKJC6WG8MCG21L: PUBLIC.BATCH_MALT FOREIGN KEY(MALT_ID) REFERENCES PUBLIC.MALT(ID) (2)"; SQL statement: delete from malt where id=? [23503-197]]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement
org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint ["FKM636T1NDS3GNKJC6WG8MCG21L: PUBLIC.BATCH_MALT FOREIGN KEY(MALT_ID) REFERENCES PUBLIC.MALT(ID) (2)"; SQL statement:
delete from malt where id=? [23503-197]]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement
Caused by: org.h2.jdbc.JdbcSQLException: Naruszenie więzów integralności: "FKM636T1NDS3GNKJC6WG8MCG21L: PUBLIC.BATCH_MALT FOREIGN KEY(MALT_ID) REFERENCES PUBLIC.MALT(ID) (2)"
Referential integrity constraint violation: "FKM636T1NDS3GNKJC6WG8MCG21L: PUBLIC.BATCH_MALT FOREIGN KEY(MALT_ID) REFERENCES PUBLIC.MALT(ID) (2)"; SQL statement:
delete from malt where id=? [23503-197]
What should I change to be able to delete Country?
Link to whole repo: https://github.com/fangirsan/maruszka-new

Why does Hibernate/Spring generate foreign key on ID field. Causes foreign key volation

I am new to Hibernate/Spring and am having an issue with autogenerated foreign keys and constrain violation. I have the following class properties:
#Id
#Column(name="MEDICATION_ID", nullable = false)
#GeneratedValue(strategy = GenerationType.AUTO)
private long medicationId;
#Column(name="PATIENT_ID")
private long patientId;
private long dosageMg; // dose for patient in mgs
private long active; // active = 1, inactive = 0
private String medicationName; // name, oxy, etc.
private String medicationCode; // global identifier for this medications
private long activeDate;
private long inactiveDate;
When I start my server I notice that it generates the following code foreign key on the medicationID
Hibernate: alter table medication add constraint FK_dbfuno3knrhmabosmfty7l3ta foreign key (all_medications_MEDICATION_ID) references medication
Then when it tries to execute this insert statement from my import.sql it throws a constraint violation error.
delete from medication;
insert into medication (medication_id, patient_id, dosage_mg, active, medication_name, medication_code, active_date,inactive_date ) values (1000, 101, 10, 1, 'Oxy', 'oxy_10', 10000, 50000);
The error reads:
Caused by: org.hsqldb.HsqlException: integrity constraint violation: NOT NULL check constraint; SYS_CT_10127 table: MEDICATION column: ALL_MEDICATIONS_MEDICATION_ID
Any ideas on why this foreign key was generated and how I can get around this constraint violation.
Thanks!

Hibernate MapKeyManyToMany gives composite key where none exists

I have a Hibernate (3.3.1) mapping of a map using a three-way join table:
#Entity
public class SiteConfiguration extends ConfigurationSet {
#ManyToMany
#MapKeyManyToMany(joinColumns=#JoinColumn(name="SiteTypeInstallationId"))
#JoinTable(
name="SiteConfig_InstConfig",
joinColumns = #JoinColumn(name="SiteConfigId"),
inverseJoinColumns = #JoinColumn(name="InstallationConfigId")
)
Map<SiteTypeInstallation, InstallationConfiguration>
installationConfigurations = new HashMap<SiteTypeInstallation, InstallationConfiguration>();
...
}
The underlying table (in Oracle 11g) is:
Name Null Type
------------------------------ -------- ----------
SITECONFIGID NOT NULL NUMBER(19)
SITETYPEINSTALLATIONID NOT NULL NUMBER(19)
INSTALLATIONCONFIGID NOT NULL NUMBER(19)
The key entity used to have a three-column primary key in the database, but is now redefined as:
#Entity
public class SiteTypeInstallation implements IdResolvable {
#Id
#GeneratedValue(generator="SiteTypeInstallationSeq", strategy= GenerationType.SEQUENCE)
#SequenceGenerator(name = "SiteTypeInstallationSeq", sequenceName = "SEQ_SiteTypeInstallation", allocationSize = 1)
long id;
#ManyToOne
#JoinColumn(name="SiteTypeId")
SiteType siteType;
#ManyToOne
#JoinColumn(name="InstalationRoleId")
InstallationRole role;
#ManyToOne
#JoinColumn(name="InstallationTypeId")
InstType type;
...
}
The table for this has a primary key 'Id' and foreign key constraints+indexes for each of the other columns:
Name Null Type
------------------------------ -------- ----------
SITETYPEID NOT NULL NUMBER(19)
INSTALLATIONROLEID NOT NULL NUMBER(19)
INSTALLATIONTYPEID NOT NULL NUMBER(19)
ID NOT NULL NUMBER(19)
For some reason, Hibernate thinks the key of the map is composite, even though it isn't, and gives me this error:
org.hibernate.MappingException: Foreign key (FK1A241BE195C69C8:SiteConfig_InstConfig [SiteTypeInstallationId])) must have same number of columns as the referenced primary key (SiteTypeInstallation [SiteTypeId,InstallationRoleId])
If I remove the annotations on installationConfigurations and make it transient, the error disappears.
I am very confused why it thinks SiteTypeInstallation has a composite key at all when #Id is clearly defining a simple key, and doubly confused why it picks exactly just those two columns. Any idea why this happens? Is it possible that JBoss (5.0 EAP) + Hibernate somehow remembers a mistaken idea of the primary key across server restarts and code redeployments?
Thanks in advance,
-Lars

Resources