Tables are created in the wrong order. SpringBoot + MySql - java

I created all the entities and linked them with primary, foreign keys. In theory, when I run the program, then all these entities should be created in the database, but the problem is that they are created in the wrong order.
For example, first the "orders" label is created, and then the "users" label, and because of this it is impossible to link them using the primary key.
Hence the question, how to make it so that hibernate understands in what order to create tables
Tables are created in the sequence shown below
Error
org.hibernate.tool.schema.spi.CommandAcceptanceException: Error executing DDL "create table orders (id bigint not null, address varchar(255), create datetime, status varchar(255), sum decimal(19,2), updated datetime, user_id bigint, primary key (id)) engine=MyISAM" via JDBC Statement
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 'create datetime, status varchar(255), sum decimal(19,2), updated datetime, user_' at line 1
application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/shop?useSSL=false&serverTimezone=UTC
spring.datasource.username=bestuser
spring.datasource.password=bestuser
spring.flyway.baseline-on-migrate=true
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.database-platform=org.hibernate.dialect.MySQL5Dialect
Bucket
#Data
#NoArgsConstructor
#AllArgsConstructor
#Builder
#Entity
#Table(name = "buckets")
public class Bucket {
private static final String SEQ_NAME = "bucket_seq";
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = SEQ_NAME)
#SequenceGenerator(name = SEQ_NAME, sequenceName = SEQ_NAME, allocationSize = 1)
private Long id;
#OneToOne
#JoinColumn(name = "user_id")
private User user;
#ManyToMany
#JoinTable(name = "buckets_products", joinColumns = #JoinColumn(name = "bucket_id"), inverseJoinColumns = #JoinColumn(name = "product_id"))
private List<Product> products;
}
Category
#Data
#NoArgsConstructor
#AllArgsConstructor
#Builder
#Entity
#Table(name = "categories")
public class Category {
private static final String SEQ_NAME = "categories_seq";
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = SEQ_NAME)
#SequenceGenerator(name = SEQ_NAME, sequenceName = SEQ_NAME, allocationSize = 1)
private Long id;
private String title;
}
Order
#Data
#NoArgsConstructor
#AllArgsConstructor
#Builder
#Entity
#Table(name = "orders")
public class Order {
private static final String SEQ_NAME = "orders_seq";
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = SEQ_NAME)
#SequenceGenerator(name = SEQ_NAME, sequenceName = SEQ_NAME, allocationSize = 1)
private Long id;
#CreationTimestamp
private LocalDateTime create;
#UpdateTimestamp
private LocalDateTime updated;
#ManyToOne
#JoinColumn(name = "user_id")
private User user;
private BigDecimal sum;
private String address;
#OneToMany(cascade = CascadeType.ALL)
private List<OrderDetails> details;
#Enumerated(EnumType.STRING)
private OrderStatus status;
}
OrderDetails
#Data
#NoArgsConstructor
#AllArgsConstructor
#Builder
#Entity
#Table(name = "orders_details")
public class OrderDetails {
private static final String SEQ_NAME = "order_details_seq";
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = SEQ_NAME)
#SequenceGenerator(name = SEQ_NAME, sequenceName = SEQ_NAME, allocationSize = 1)
private Long id;
#ManyToOne
#JoinColumn(name = "order_id")
private Order order;
#ManyToOne
#JoinColumn(name = "product_id")
private Product product;
private BigDecimal amount;
private BigDecimal price;
}
OrderStatus
public enum OrderStatus {
NEW, APPROVED, CANCELED, PAID, CLOSED
}
Product
#Data
#NoArgsConstructor
#AllArgsConstructor
#Builder
#Entity
#Table(name = "products")
public class Product {
private static final String SEQ_NAME = "product_seq";
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = SEQ_NAME)
#SequenceGenerator(name = SEQ_NAME, sequenceName = SEQ_NAME, allocationSize = 1)
private Long id;
private String title;
private BigDecimal price;
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(name = "products_categories", joinColumns = #JoinColumn(name = "product_id"), inverseJoinColumns = #JoinColumn(name = "category_id"))
private List<Category> categories;
}
Role
public enum Role {
CLIENT, MANAGER, ADMIN
}
User
#Data
#NoArgsConstructor
#AllArgsConstructor
#Builder
#Entity
#Table(name = "users")
public class User {
private static final String SEQ_NAME = "user_seq";
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = SEQ_NAME)
#SequenceGenerator(name = SEQ_NAME, sequenceName = SEQ_NAME, allocationSize = 1)
private Long id;
private String name;
private String password;
private String email;
private boolean active;
#Enumerated(EnumType.STRING)
private Role role;
#OneToOne(cascade = CascadeType.REMOVE)
private Bucket bucket;
}

you can use #Temporal This annotation must be specified for persistent fields or properties of type java.util.Date and java.util.Calendar
see What is the use of the #Temporal annotation in Hibernate?
Put a annotation on each date or time field as follows :
#Temporal(TemporalType.TIMESTAMP)
or
#Temporal(TemporalType.DATE)
or
#Temporal(TemporalType.TIME)

You can't achieved table creation sequence by hibernate. You can use migration script tool, like Flyway or Liquibase
And your application.properties (flyway sample) set next properties
spring.flyway.url=
spring.flyway.user=
spring.flyway.password=
spring.flyway.schemas=public
spring.flyway.locations=classpath:/your/path
spring.jpa.hibernate.ddl-auto=validate

Related

Get ElementCollection with native query

I have this entity that i need to join with another unrelated entity, this is why I am using a native query.
#Entity
#Table(name = "surveillance_questionnaires")
#Setter #Getter
public class SurveillanceQuestionnaire {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "surveillance_questionnaires_sequence")
#SequenceGenerator(name = "surveillance_questionnaires_sequence", allocationSize = 5)
private Integer id;
#ElementCollection
#Fetch(FetchMode.JOIN)
#CollectionTable(name = "surveillance_questionnaires_years",
joinColumns = #JoinColumn(name = "id", referencedColumnName = "id"))
#Column(name = "year")
private List<String> years;
...
}
Is there any way to fetch the SurveillanceQuestionnaire entity with its ElementCollection (years) using native query?

JPA working with bidirectional relationship

I'm new to jpa, so please don't be strict with me. Maybe my question is stupid. But. I don't quite understand how to work with the bidirectional relationship. For example I have the following classes:
#Data
#NoArgsConstructor
#AllArgsConstructor
#Entity
public class Book {
#Id
#SequenceGenerator(name = "book_id_seq_gen", sequenceName = "book_id_seq", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "book_id_seq_gen")
private long id;
private String name;
private int year;
#ManyToOne
private Writer writer;
private String description;
private int downloadNumber;
#ManyToMany
#JoinTable(name = "book_genre",
joinColumns = #JoinColumn(name = "book_id"),
inverseJoinColumns = #JoinColumn(name = "genre_id")
)
private Set<Genre> genres;
}
#Data
#NoArgsConstructor
#AllArgsConstructor
#Entity
public class Writer {
#Id
#SequenceGenerator(name = "writer_id_seq_gen", sequenceName = "writer_id_seq", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "writer_id_seq_gen")
private long id;
#NotNull(message = "Name cannot be null")
#Length(min = 1, max = 100)
private String name;
#NotNull(message = "Surname cannot be null")
#Length(min = 1, max = 100)
private String surname;
private String description;
#OneToMany(mappedBy = "writer")
private List<Book> books;
}
I'm working with REST, so when I'm trying to return object back, I get a cycle. Okay, I fixed it with annotations for JSON. But. When I'm just trying to work with a collection of books in the writer I get the cycle. I can't work with the collection and I can't work with the writer either. So how to work with it at all?

Hibernate/JPA incorrect join in Spring Boot Application

See code below for my 2 entity classes - when I call the findAll() method from my OrigRepository class, it joins these two tables using both primary keys. I want the join to be between the primary key of the Orig table and the foreign key entry in the MsgResponse table ("OrigID") - any sugggestions?
Orig Entity
#Entity
#Table(name = "originator")
public class Orig {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "OrigID")
private int OrigID;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "OrigID")
private MsgResponse responseInfo;
}
MsgResponse Entity
#Entity
#Table(name = "message_response")
public class MsgResponse {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "ID")
private int responseId;
#Column(name = "OrigID")
private int OrigId;
#OneToOne(mappedBy="responseInfo")
private Orig OrigInfo;
}
I suggest you to see the jpa documentation
here.
Example 1 should be your case
Try to swap relation ownership, that is:
#Entity
#Table(name = "originator")
public class Orig {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "OrigID")
private int OrigID;
#OneToOne(mappedBy="origInfo")
private MsgResponse responseInfo;
}
#Entity
#Table(name = "message_response")
public class MsgResponse {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "ID")
private int responseId;
// #Column(name = "OrigID")
// private int origId;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "OrigID")
private Orig origInfo;
}
Note that the #JoinColum annotation is in now in the MsgResponse entity. This is because in a #OneToOne the join column refers to the source entity (see here).
Hope this could help.

Hibernate reverse one to one undirectional mapping

I have two classes Cards and CardBalance. In my DB sсhema table card_balance has foreign key on table cards. But in ORM I want that entity Cards has properties CardBalance, and entity CardBalance does't have propertie Cards.
I try do this in next way:
#Entity
#Table(name = "CARD_BALANCE")
public class CardBalance {
#Id
#Column(name = "BALANCE_ID")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "CARD_BALANCE_SEQ")
#SequenceGenerator(name = "CARD_BALANCE_SEQ", sequenceName = "CARD_BALANCE_SEQ")
private Long balanceId;
#Column(name="CARD_ID")
private Long cardId;
}
#Entity
#Table(name = "CARDS")
public class Cards implements Serializable {
#Id
#Column(name = "CARD_ID")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "CARDS_SEQ")
#SequenceGenerator(name = "CARDS_SEQ", sequenceName = "CARDS_SEQ")
private Long cardId;
#Column(name = "CARD_NAME", length = 30, unique = true)
private String cardName;
#Column(name="PERSON_ID")
private Long personId;
#Column(name = "CARD_KEY", nullable = false)
private long cardKey;
#OneToOne
#JoinColumn(name="TYPE_ID", nullable = false)
private TypeCard typeCard;
#OneToOne
#JoinColumn(name="CARD_ID", nullable = false)
private CardBalance cardBalance;
#OneToMany(fetch = FetchType.LAZY)
#JoinColumn(name="CARD_ID")
public Set<BalanceHist> balanceHists = new HashSet<>();
#OneToMany(fetch = FetchType.LAZY)
#JoinColumn(name="CARD_ID")
public Set<Events> events = new HashSet<>();
}
but it does't work. How I can solve this problem?
First of all, you have a mistake in your #JoinColumn, it should be:
#OneToOne
#JoinColumn(name="BALANCE_ID", nullable = false)
private CardBalance cardBalance;

why is Hibernate selecting same columns twice?

Hibernate:
/* load entities.Department */ select
department0_.name as name4_0_,
department0_.id as id4_0_
from
J_DEPT department0_
where
department0_.name=?
Hibernate:
/* load one-to-many entities.Department.employees */ select
employees0_.dept as dept4_1_,
employees0_.id as id1_,
employees0_.id as id5_0_,
employees0_.dept as dept5_0_,
employees0_.name as name5_0_
from
J_EMP employees0_
where
employees0_.dept=?
Note that ID and DEPT columns are selected twice.
#Entity
#Table(name = "J_EMP")
public class Employee {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "mySeq")
#SequenceGenerator(name = "mySeq", sequenceName = "CNTRY_SEQ")
private Long id;
private String name;
#ManyToOne
#JoinColumn(name = "dept")
private Department deptNameInEmp;
}
#Entity
#Table(name = "J_DEPT")
public class Department {
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "mySeq")
#SequenceGenerator(name = "mySeq", sequenceName = "CNTRY_SEQ")
private Long id;
#Id
#Column(name = "name")
private String deptNameInDeptEntity;
#OneToMany(mappedBy = "deptNameInEmp")
Set<Employee> employees;
}
UPDATED:
It was done intentionally to put #GeneratedValue on non-PK. However, now I've updated as you specified.
I've copy-pasted the new queries:
Hibernate:
/* load entities.Department */ select
department0_.id as id4_0_,
department0_.name as name4_0_
from
J_DEPT department0_
where
department0_.id=?
Hibernate:
/* load one-to-many entities.Department.employees */ select
employees0_.dept as dept4_1_,
employees0_.id as id1_,
employees0_.id as id5_0_,
employees0_.dept as dept5_0_,
employees0_.name as name5_0_
from
J_EMP employees0_
where
employees0_.dept=?
I guess its still the same.
And here are the tables:
CREATE TABLE "XYZ"."J_DEPT"
( "ID" NUMBER(*,0) NOT NULL ENABLE,
"NAME" VARCHAR2(255 BYTE) NOT NULL ENABLE,
CONSTRAINT "J_DEPT_PK" PRIMARY KEY ("ID")
)
CREATE TABLE "XYZ"."J_EMP"
( "ID" NUMBER NOT NULL ENABLE,
"NAME" VARCHAR2(255 BYTE),
"DEPT" NUMBER NOT NULL ENABLE,
CONSTRAINT "J_EMP_PK" PRIMARY KEY ("ID"))
here is the code -i'm pasting here as it is :
#Entity
#Table(name = "J_DEPT")
public class Department {
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "mySeq")
#SequenceGenerator(name = "mySeq", sequenceName = "CNTRY_SEQ")
#Id
private Long id;
#Column(name = "name")
private String deptNameInDeptEntity;
#OneToMany(mappedBy = "deptNameInEmp")
Set<Employee> employees;
public Set<Employee> getEmployees() {
return employees;
}
}
#Entity
#Table(name = "J_EMP")
public class Employee {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "mySeq")
#SequenceGenerator(name = "mySeq", sequenceName = "CNTRY_SEQ")
private Long id;
private String name;
#ManyToOne
#JoinColumn(name = "dept")
private Department deptNameInEmp;
public Employee() {
}
And here is the test case:
#RunWith(SpringJUnit4ClassRunner.class)
#TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = false)
#ContextConfiguration(locations = { "classpath:test-applicationContext.xml" })
#Transactional
public class EmpTest {
#Autowired
private SessionFactory sessionFactory;
#Test
public void testDept() {
final Department find = (Department) sessionFactory.getCurrentSession()
.get(Department.class, Long.parseLong("1"));
System.out.println("find res = " + find);
}
}
Probably because of this part:
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "mySeq")
#SequenceGenerator(name = "mySeq", sequenceName = "CNTRY_SEQ")
private Long id;
#Id
#Column(name = "name")
private String deptNameInDeptEntity;
There is something wrong here, the GeneratedValue cannot be applied to a non PK. Did you mean:
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "mySeq")
#SequenceGenerator(name = "mySeq", sequenceName = "CNTRY_SEQ")
private Long id;
#Column(name = "name")
private String deptNameInDeptEntity;
If not, and if this was intentional, please explain your goal and show your table(s).
Update: I can't reproduce the problem. I copy pasted the code you provided and here is the query I get:
select
employee37x0_.id as id135_,
employee37x0_.dept as dept135_,
employee37x0_.name as name135_
from
J_EMP employee37x0_
where
employee37x0_.id=?
Works as expected.
A Google search on "hibernate duplicate aliases" reveals some (old) issues so I don't exclude anything but I couldn't find any proof of recent existing problems. Can you provide a test case (using an embedded database)?

Categories