Error executing DDL alter table if exists task.city - java

The error Error executing DDL "alter table if exists task.city add constraint FKtjrg7h2j3ehgycr3usqjgnc2u foreign key (id) references task.house" via JDBC Statement" I Don't understand how to solve it, I was already looking for a solution, but I check my database and Entity, everything is correct. I created the database from scratch myself. I work in Postgresql. Added the error log.
Properties
spring.datasource.url=jdbc:postgresql://localhost:5432/innotechnum
spring.datasource.username=***
spring.datasource.password=***
spring.datasource.driver-class-name=org.postgresql.Driver
spring.jpa.database=postgresql
spring.jpa.hibernate.ddl-auto=update
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQL10Dialect
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true
spring.jpa.open-in-view= true
spring.jpa.show-sql=true
City
#Data
#Entity
#Table(name = "city", schema = "task")
public class City {
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name = "id_region", nullable = false)
private Integer id_region;
#Column(name = "name", nullable = false)
private String name;
}
house
#Data
#Entity
#Table (name = "house", schema = "task")
public class House {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#OneToMany(cascade = {CascadeType.DETACH, CascadeType.MERGE, CascadeType.PERSIST,
CascadeType.REFRESH
})
#JoinColumn(name = "id")
private Set<City> city;
#OneToMany(mappedBy = "house")
private Set<Contract> contract;
#Column(name = "id_landlord", nullable = false)
private Long id_landlord;
#Column(name = "outside", nullable = false)
private String outside;
#Column(name = "rooms", nullable = false)
private Integer rooms;
#Column(name = "price", nullable = false)
private Double price;
#Column(name = "description", nullable = false)
private String description;
}
LOGS:
org.hibernate.tool.schema.spi.CommandAcceptanceException: Error executing DDL "alter table if exists task.city add constraint FKtjrg7h2j3ehgycr3usqjgnc2u foreign key (id) references task.house" via JDBC Statement
at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(GenerationTargetToDatabase.java:67) ~[hibernate-core-5.4.20.Final.jar:5.4.20.Final]
at org.hibernate.tool.schema.internal.AbstractSchemaMigrator.applySqlString(AbstractSchemaMigrator.java:559) ~[hibernate-core-5.4.20.Final.jar:5.4.20.Final]
at
...
This is the code that Postgresql gives me:
CREATE TABLE task.city
(
id integer NOT NULL DEFAULT nextval('task.city_id_seq'::regclass),
id_region integer NOT NULL,
name character varying(250) COLLATE pg_catalog."default" NOT NULL,
CONSTRAINT city_pkey PRIMARY KEY (id)
)
TABLESPACE pg_default;
ALTER TABLE task.city
OWNER to root;

You should not use unidirectional #OneToMany association. Try to add the
#ManyToOne(fetchType = LAZY)
#JoinColumn(name = "house_id")
private House house;
to the City class.
P.S. Do you sure you need one-to-many association from house to city but not vice versa? City may have many houses, but house belongs to the particular city.

Hmm, try
public class House {
...
#ManyToOne(optional = false)
#JoinColumn(name = "city_id", referencedColumnName = "id")
private Set<City> city;
...
}
btw,
should not use #Data lombok in an entity class
spring.jpa.hibernate.ddl-auto=update can change update to none. You should manage schema on your own.

Related

Cannot delete or update a parent row: a foreign key constraint fails (`liked_songs`, CONSTRAINT FK (`songs_id`) REFERENCES `songs` (`id`))

I'm trying to make an app that has users songs and two types of playlist(regular and for liked songs).
#MappedSuperclass
public abstract class BasePlaylist {
#Id
#GeneratedValue(generator = "UUID")
#GenericGenerator(
name = "UUID",
strategy = "org.hibernate.id.UUIDGenerator"
)
#Type(type = "uuid-char")
private UUID id;
#Column(nullable = false)
private String name;
#ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.DETACH)
private Set<Song> songs;
private String imageUrl;
private LocalDateTime creationTime;
}
#Entity
#Table(name = "songs")
public class Song {
#Id
#GeneratedValue(generator = "UUID")
#GenericGenerator(
name = "UUID",
strategy = "org.hibernate.id.UUIDGenerator"
)
#Type(type = "uuid-char")
private UUID id;
#Column(nullable = false)
private String title;
#ManyToOne(optional = false)
private User creator;
#Column(unique = true, nullable = false)
private String songUrl;
private LocalDateTime creationTime;
}
the only difference between the two types of playlists is the relationship with the users (onetoone and manytomany). The problem I'm facing is when I try to delete a song I get Cannot delete or update a parent row: a foreign key constraint fails. I thought putting the cascade detach on the songs set would fix the problem but it didn't. I tried with cascade all but it didn't do anything either. I even tried making the relations bidirectional and putting cascadetype all on the playlists but I get the same error. My goal is to remove all song relations on delete.

Table doesn't get created JPA

Table "books" doesn't get created somehow.
My books table:
#Entity
#Table(name = "books")
public class Book {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id", nullable = false)
private Long id;
#ManyToOne(cascade = CascadeType.PERSIST)
#JoinColumn(name = "publisher_id", nullable = false)
private Publisher publisher;
#ManyToMany
#JoinTable(name = "authors_books", joinColumns = #JoinColumn(name = "book_id"),
inverseJoinColumns = #JoinColumn(name = "author_id"))
private Set<Author> authors;
#Column(name = "is_rented", nullable = false, columnDefinition = "DEFAULT FALSE")
private Boolean is_rented;
#Column(name = "isbn", nullable = false, unique = true, length = 300)
private String isbn;
Publishers table:
#Entity
#Table(name = "publishers")
public class Publisher {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id", nullable = false)
private Long id;
#OneToMany(mappedBy = "publisher")
private Set<Book> books;
Authors table:
#Entity
#Table(name = "authors")
public class Author {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id", nullable = false)
private Long id;
#ManyToMany(mappedBy = "authors")
private Set<Book> books;
application.properties:
spring.jpa.hibernate.ddl-auto=create
spring.jpa.database=mysql
spring.datasource.url=jdbc:mysql://${MYSQL_HOST:localhost}:3306/<schema_name>?createDatabaseIfNotExist=true
spring.datasource.username=${MYSQL_USERNAME}
spring.datasource.password=${MYSQL_PASSWORD}
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
Omitted other fields, only reference fields left. I also ovverrid equals and hashcode methods in all entities. And I have empty constructors and full constructors, as well as getters and setters in all of them. Also added #EntityScan to SpringBootApplication file.
I get error:
Table '<schema_name>.authors_books' doesn't exist.
Table '<schema_name>.books' doesn't exist.
But all other tables do exist. Does anybody see what I am missing?
EDIT
Checked database manually. Table "authors_books" DOES exist(despite jpa telling me that it doesn't). Only "books" DOES NOT.
EDIT #2
I added to application.properties:
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
And it shows me:
org.hibernate.tool.schema.spi.CommandAcceptanceException: Error executing DDL "
create table books (
id bigint not null,
amount integer not null,
image varchar(300),
is_rented DEFAULT FALSE,
isbn varchar(300) not null,
published_on date,
title varchar(300) not null,
publisher_id bigint not null,
primary key (id)
) engine=InnoDB"
Caused by: java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'DEFAULT FALSE,
isbn varchar(300) not null,
' at line 5
Looks like problem was with:
#Column(name = "is_rented", nullable = false, columnDefinition = "DEFAULT FALSE")
private Boolean is_rented;
If you configure columnDefinition, then Hibernate does not care about java-based data type you provided.
So the SQL was like:
is_rented DEFAULT FALSE,
which obviously lacks data type.
So I changed it into:
#Column(name = "is_rented", columnDefinition = "BOOLEAN DEFAULT FALSE")
private Boolean is_rented;
And it worked :)

Hibernate composite key with composite key

I'm currently mapping a complex database schema wqith HIbernate and I have hit a wall with an entity which has a composite key with another composite key.
I have this table for roles with a composite key (site_id, id)
CREATE TABLE IF NOT EXISTS core.roles
(
id uuid NOT NULL DEFAULT gen_random_uuid(),
name character varying(100) NOT NULL,
is_system_role boolean NOT NULL DEFAULT FALSE,
site_id uuid NOT NULL,
created_at timestamp with time zone NOT NULL DEFAULT now(),
updated_at timestamp with time zone NOT NULL DEFAULT now(),
created_by uuid NOT NULL,
updated_by uuid NOT NULL,
CONSTRAINT roles_pkey PRIMARY KEY (site_id, id),
CONSTRAINT roles_name_key UNIQUE (site_id, name),
CONSTRAINT roles_site_id_fkey FOREIGN KEY (site_id)
REFERENCES core.sites (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE CASCADE,
CONSTRAINT roles_created_by_fkey FOREIGN KEY (created_by)
REFERENCES core.users (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE RESTRICT,
CONSTRAINT roles_updated_by_fkey FOREIGN KEY (updated_by)
REFERENCES core.users (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE RESTRICT
);
And I have this table with a composite key which also uses the previous one.
CREATE TABLE IF NOT EXISTS core.user_site_roles
(
user_id uuid NOT NULL,
site_id uuid NOT NULL,
role_id uuid NOT NULL,
created_at timestamp with time zone NOT NULL DEFAULT now(),
created_by uuid NOT NULL,
CONSTRAINT user_site_roles_pkey PRIMARY KEY (site_id, user_id, role_id),
CONSTRAINT user_site_roles_site_id_fkey FOREIGN KEY (site_id)
REFERENCES core.sites (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE CASCADE,
CONSTRAINT user_site_roles_role_id_fkey FOREIGN KEY (site_id, role_id)
REFERENCES core.roles (site_id, id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE CASCADE,
CONSTRAINT user_site_roles_user_id_fkey FOREIGN KEY (user_id)
REFERENCES core.users (id) MATCH SIMPLE
ON UPDATE NO ACTION
CONSTRAINT user_site_roles_created_by_fkey FOREIGN KEY (created_by)
REFERENCES core.users (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE RESTRICT
);
My current mapping for the roles one which is working is:
#Embeddable
public class CommonId implements Serializable {
#Type(type = "pg-id-uuid")
#Column(columnDefinition = "uuid", updatable = false)
private UUID id;
#Type(type = "pg-id-uuid")
#Column(name = "site_id", columnDefinition = "uuid", updatable = false)
private UUID siteId;
}
#Entity
#Table(name = "roles", schema = "core")
#Data
#TypeDefs({
#TypeDef(name = "pg-id-uuid", typeClass = PostgresIdUUIDType.class)
})
public class Role extends AuditAtBy implements Serializable {
#EmbeddedId
private CommonId roleId;
#ManyToOne
#MapsId("siteId")
#OnDelete(action = OnDeleteAction.CASCADE)
private Site site;
#Column(nullable = false, unique = true, length = 100)
private String name;
#Column(name = "is_system_role", nullable = false)
private boolean isSystemRole;
}
I was trying something similar with the composite Key for the UserSiteRole but Hibernate tells me that it needs to columns to map the roleId when in the table I have just the id but the PK is form by the two values as you can see in the script, not sure how to map it to be honest.
#Embeddable
public class UserSiteRoleId implements Serializable {
#Type(type = "pg-id-uuid")
#Column(columnDefinition = "uuid", updatable = false)
private UUID userId;
#Type(type = "pg-id-uuid")
#Column(name = "site_id", columnDefinition = "uuid", updatable = false)
private UUID siteId;
#Type(type = "pg-id-uuid")
#Column(name = "role_id", columnDefinition = "uuid", updatable = false)
private UUID roleId;
}
#Entity
#Table(name = "user_site_roles", schema = "core")
#Data
#TypeDefs({
#TypeDef(name = "pg-id-uuid", typeClass = PostgresIdUUIDType.class)
})
public class UserSiteRole extends AuditCreated implements Serializable {
#EmbeddedId
private UserSiteRoleId userSiteRoleId;
#ManyToOne
#MapsId("userId")
#JoinColumn(name = "user_id", columnDefinition = "uuid", nullable = false)
#Type(type = "pg-id-uuid")
#OnDelete(action = OnDeleteAction.CASCADE)
private User user;
#ManyToOne
#MapsId("siteId")
#JoinColumn(name = "site_id", columnDefinition = "uuid", nullable = false)
#Type(type = "pg-id-uuid")
#OnDelete(action = OnDeleteAction.CASCADE)
private Site site;
#ManyToOne
#MapsId("roleId")
#JoinColumn(name = "role_id", columnDefinition = "uuid", nullable = false)
#Type(type = "pg-id-uuid")
#OnDelete(action = OnDeleteAction.CASCADE)
private Role role;
}
I would appreciate any ideas about how to map it, I had never had to map such a complex relationship so not sure how to proceed in this case.
Does this answer your question? jpa hibernate composite foreign key mapping
Actually that was useful as it made it clear that we could change the mapping from embeddedId to IdClass and make it work.
This is our new IdClass, pretty simple:
#Data
#NoArgsConstructor
#AllArgsConstructor
public class UserSiteRoleId implements Serializable {
private User user;
private Site site;
private Role role;
}
And the entity itself working just inf e is as follows.
#Entity
#Table(name = "user_site_roles", schema = "core")
#Data
#TypeDefs({
#TypeDef(name = "pg-id-uuid", typeClass = PostgresIdUUIDType.class)
})
#IdClass(UserSiteRoleId.class)
public class UserSiteRole extends AuditCreated implements Serializable {
#Id
#ManyToOne
#JoinColumn(name = "user_id", columnDefinition = "uuid", nullable = false)
#Type(type = "pg-id-uuid")
#OnDelete(action = OnDeleteAction.CASCADE)
private User user;
#Id
#ManyToOne
#JoinColumn(name = "site_id", columnDefinition = "uuid", nullable = false)
#Type(type = "pg-id-uuid")
#OnDelete(action = OnDeleteAction.CASCADE)
private Site site;
#Id
#ManyToOne
#JoinColumns({
#JoinColumn(name = "role_id", referencedColumnName="id", columnDefinition = "uuid", insertable = false, updatable = false),
#JoinColumn(name = "site_id", referencedColumnName="site_id", columnDefinition = "uuid", insertable = false, updatable = false)
})
#Type(type = "pg-id-uuid")
#OnDelete(action = OnDeleteAction.CASCADE)
private Role role;
}

#ColumnTransformer have no alias when select column

I need encrypted and decrypted some column such.
#Entity
#Table(name = "Person")
#Data
public class Person {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID", unique = true, nullable = false)
private Long id;
#Column(name = "NAME", columnDefinition = "varchar")
#ColumnTransformer(read = "pgp_sym_decrypt(decode(NAME, 'hex'), 'key')", write = "encode(pgp_sym_encrypt(?, 'key'), 'hex')")
private String name;
#ManyToOne
#JoinColumn(name = "PARENT_ID")
private Person parent;
}
When I use PersonRepository.findOneByParentId(10L); and see log sql is
select
person0_."id" as id1_99_,
pgp_sym_decrypt(decode(NAME, 'hex'), 'key') as name2_99_
from
"public"."person" person0_
left outer join
"public"."person" person1_
on person0_."parent_id"=person1_."id"
where
person1_."id"=?
This error message
ERROR: column reference "name" is ambiguous
Why #ColumnTransformer don't add table alias of column "name", What should I do ?
I had this issue and adding the forColumn property worked for me.
#ColumnTransformer(
forColumn = "lastName",

EclipseLink #CascadeOnDelete only works sometimes?

I have two tables, "books" and "bookstores" that both have a #OneToMany reference to the "book_to_bookstore" table which hols the information how many books are in which bookstore.
If either a book or a bookstore is deleted, that information should vanish, too.
Therefore I use the standard JPA CascadeType.ALL and orphanRemoval=true. To make "proper" SQL schemas that also work when accessing it not with Java, I added the EclipseLink specific #CascadeOnDelete annotation, expecting the CASCADE ON DELETE to appear after both FOREIGN KEY statements.
Interestingly though, it only appears after one of them which I just can't explain!
I tried the DDL generation for MySQL and PostgreSQL but both are the same.
Why?
A compileable mini project is here:
svn+ssh://lathspell#svn.code.sf.net/p/lathspellsphp/code/java_test_eclipselink_cascade_bug
The important classes:
public class Bookstore implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "id")
private Integer id;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "bookstoreId", orphanRemoval = true)
#CascadeOnDelete
private List<BookToBookstore> bookToBookstoreList;
...
public class Book implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "id")
private Integer id;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "bookId", orphanRemoval = true)
#CascadeOnDelete
private List<BookToBookstore> bookToBookstoreList;
...
public class BookToBookstore implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "id")
private Integer id;
#JoinColumn(name = "bookstore_id", referencedColumnName = "id")
#ManyToOne(optional = false)
private Bookstore bookstoreId;
#JoinColumn(name = "book_id", referencedColumnName = "id")
#ManyToOne(optional = false)
private Book bookId;
...
The generated SQL for MySQL, note the missing CASCADE ON DELETE in the last line:
CREATE TABLE books (id INTEGER AUTO_INCREMENT NOT NULL, PRIMARY KEY (id))
CREATE TABLE book_to_bookstore (id INTEGER AUTO_INCREMENT NOT NULL, book_id INTEGER, bookstore_id INTEGER, PRIMARY KEY (id))
CREATE TABLE bookstores (id INTEGER AUTO_INCREMENT NOT NULL, PRIMARY KEY (id))
ALTER TABLE book_to_bookstore ADD CONSTRAINT FK_book_to_bookstore_book_id FOREIGN KEY (book_id) REFERENCES books (id) ON DELETE CASCADE
ALTER TABLE book_to_bookstore ADD CONSTRAINT FK_book_to_bookstore_bookstore_id FOREIGN KEY (bookstore_id) REFERENCES bookstores (id)

Categories