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 :)
Related
I have two entities:
#Entity
#Table(name = "entity_a")
#Audited
public class EntityA {
#Column(name = "entity_a_uuid", columnDefinition = "char", updatable = false)
#Type(type = "uuid-char")
private UUID uuid = UUID.randomUUID();
/**
* #deprecated in favor of uuid
*/
#Deprecated
#Id
#GeneratedValue
#Column(name = "entity_a_id")
private Integer id;
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
#JoinColumn(name = "entity_a_id", nullable = false)
#BatchSize(size = 100)
#NotAudited
private List<EntityB> entityBs = new ArrayList<>();
}
and
#Entity
#Audited
#Table(name = "entity_b")
public class EntityB {
#Id
#Column(name = "entity_b_uuid", columnDefinition = "char", updatable = false)
#Type(type = "uuid-char")
private UUID uuid = UUID.randomUUID();
#ManyToOne(optional = false, fetch = FetchType.LAZY)
#JoinColumn(name = "entity_a_id", nullable = false, insertable = false, updatable = false)
private EntityA entityA;
}
Each is correctly audited into two tables entity_a_audit and entity_b_audit. However, the entity_a_id field in entity_b_audit is always null.
Some details:
If I do not have the #NotAudited in EntityA, I will get an error that says something to the effect of: The table EntityA_EntityB_audit does not exist. This seems like it's trying to audit them as a single table, which I do not want.
I have tried applying #Audited(targetAuditMode = elationTargetAuditMode.NOT_AUDITED) to each side. If applied only in EntityA, I get the above error. If applied only in EntityB, nothing changes. If applied in both, I get the error above. If applied to neither, I get the error above.
I suspect the entity_a_id is null in entity_b_audit because the id isn't generated until EntityA hits the DB. entity_a_id is auto-incrementing in the entity_a table.
Using hibernate-envers-5.4.32.Final.jar
Ultimately, I would like for entity_a_id to not be null in entity_b_audit. Alternatively, if I could somehow get entity_a_uuid to be captured instead, that would also suffice.
Any help would be greatly appreciated! Thanks.
You marked the column as insertable = false, updatable = false, so there is nothing to audit here, because Hibernate can never change the value of that column.
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.
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",
I'm trying to map the following case in JPA with Annotations:
DB Model
So, we have a root object that has a relation with the source which we are going to save in our transaction, but after a processing of that root object we will obtain the result object
Here my mapping:
public class Root {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name="source_id", unique= false, nullable=false, insertable=true, updatable=false)
private Source source;
#Column(name = "label", nullable = true, insertable = true, updatable = false)
private String label;
}
public class Source {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "label", nullable = true, insertable = true, updatable = false)
private String label;
}
public class Result {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#OneToOne(cascade = CascadeType.MERGE)
#JoinColumn(name="source_id", unique= false, nullable=false, insertable=true, updatable=false)
private Source source;
#Column(name = "label", nullable = true, insertable = true, updatable = false)
private String label;
}
My UseCase:
I save the object Source & Root
MYSQL:
INSERT INTO source (label) VALUES ("FIRST"); -- id: 1
INSERT INTO root (source_id, label) VALUES (1, "MY FIRST");
So then processing, i want to save the object Result to link this value with the source object, but i want to only link for SELECT (and not for INSERT/UPDATE/REMOVE)
My code with lombok:
SourceEntity source = SourceEntity.builder().id(root.getId()).build();
ResultEntity result = ResultEntity.builder().source(source).label("REFERENCE TO FIRST").build();
dao.save(result);
Error:
Cannot add or update a child row: a foreign key constraint fails (`mydb`.`result`, CONSTRAINT `result_fk0` FOREIGN KEY (`source_id`) REFERENCES `source` (`id`))
I understand that in the mapping I am doing something wrong but I can not find the error, maybe the cascadeType? I tried CascadeType.DETACH too.
Thanks,
I have an ER relationship from a legacy DB (MS SQL Server based as below
The way that I'm currently trying to convert this to the JPA 2.1 style is as below
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
public class Orders implements Serializable {
#Id
#GeneratedValue
#Column(name = "OrderNumber", nullable = false)
private Integer orderNumber;
#ElementCollection(fetch = FetchType.EAGER)
#CollectionTable(
name = "OrderHistory",
joinColumns = {
#JoinColumn(name = "OrderNumber", referencedColumnName = "OrderNumber", nullable = false)
}
)
private List<OrderHistory> orderHistory;
----Other properties, Getters and Setters
}
#Entity
#PrimaryKeyJoinColumn(name = "OrderNumber")
public class SpecialOrders extends Orders implements Serializable {
#JoinColumn(name = "OrderNumber", referencedColumnName = "OrderNumber", nullable = false)
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
#Fetch(FetchMode.SELECT)
#OrderBy("sequenceNumber ASC")
private List<Items> items;
----Other properties, Getters and Setters
}
#Entity
#IdClass(ItemsPK.class)
public class Items implements Serializable {
#Id
#Column(name = "OrderNumber", nullable = false, insertable = false, updatable = false)
private Integer orderNumber;
#Id
#Column(name = "SequenceNumber", nullable = false)
private Integer sequenceNumber;
#ElementCollection(fetch = FetchType.EAGER)
#CollectionTable(
name = "CustomOptions",
joinColumns = {
#JoinColumn(name = "OrderNumber", referencedColumnName = "OrderNumber", nullable = false),
#JoinColumn(name = "SequenceNumber", referencedColumnName = "SequenceNumber", nullable = false)
}
)
private List<CustomOptions> customOptions;
----Other properties, Getters and Setters
}
#Entity
public class ItemsPK implements Serializable {
#Id
#Column(name = "OrderNumber", nullable = false, insertable = false, updatable = false)
private Integer orderNumber;
#Id
#Column(name = "SequenceNumber", nullable = false)
private Integer sequenceNumber;
----Getters and Setters
}
#Entity
#IdClass(CustomOptionsPK.class)
public class CustomOptions implements Serializable {
#Id
#Column(name = "OrderNumber", nullable = false, insertable = false, updatable = false)
private Integer orderNumber;
#Id
#Column(name = "SequenceNumber", nullable = false)
private Integer sequenceNumber;
#Id
#Column(name = "OptionNumber", nullable = false)
private Integer optionNumber;
----Other properties, Getters and Setters
}
public class CustomOptionsPK implements Serializable {
#Id
#Column(name = "OrderNumber", nullable = false, insertable = false, updatable = false)
private Integer orderNumber;
#Id
#Column(name = "SequenceNumber", nullable = false)
private Integer sequenceNumber;
#Id
#Column(name = "OptionNumber", nullable = false)
private Integer optionNumber;
----Getters and Setters
}
With the above code, I see that hibernate does below
INSERTs into Orders and gets the GeneratedId for OrderNumber
INSERTs into SpecialOrders, using the orderNumber retrieved above.
Attemps to INSERT into Items table, with a NULL value in the orderNumber and then fails because the orderNumber is a NOT NULL column.
Subsequently, If add a "Simple" primary key to Items table and make the orderNumber as a NULLable column, then the below happens:
INSERTs into Orders and gets the GeneratedId for OrderNumber
INSERTs into SpecialOrders, using the orderNumber retrieved above.
INSERTs into Items table with orderNumber as NULL value and gets the generated id of the Items table row.
Updates the row of Items table with the orderNumber from parent, using the retrieved id for Items.
Attemps to INSERT into CustomOptions table, with a NULL value in the orderNumber and then fails because the orderNumber is a NOT NULL column.
As per the above sequence, it seems that:
Composite Primary key doesnt seem to be working correctly or not supported.
Hibernate is handling the OneToMany relationship inefficiently by issuing an INSERT followed by an UPDATE, instead of just an insert.
Any idea if my understanding is correct? The only way of fixing this issue seems to be that I need to remove the composite primary key and replace it with a simple one.