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?
Related
I am using queryDSL to fetch the inner collection of data and failed to do so. My entities are
#Entity
#Table(name = "countries")
#Setter
#Getter
public class Country {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long countryId;
#Column(name = "name")
private String name;
#Column(name = "data")
private String data;
#OneToOne(mappedBy = "country")
private State stateJoin;
}
#Entity
#Table(name = "states")
#Setter
#Getter
public class State {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long stateId;
#Column(name = "name")
private String name;
#Column(name = "count")
private String count;
#Column(name = "co_id")
private Long countryId;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "co_id", referencedColumnName = "id", updatable = false, insertable = false)
private Country country;
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name = "state_id", referencedColumnName = "id")
private Set<Town> towns;
}
#Entity
#Table(name = "towns")
#Setter
#Getter
public class Town {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "town_id")
private Long townId;
#Column(name = "name")
private String name;
#Column(name = "people_count")
private String peopleCount;
#Column(name = "st_id")
private Long stateId;
}
and in querydsl i am trying below query and always failing to retrieve inner collection towns
List<Expression> childGroup = new ArrayList<>();
query.from(countries);
childGroup.addAll(Arrays.asList(countries.name, countries.data, countries.stateJoin));
query.join(countries.stateJoin, State);
childGroup.add(Projections.bean(State.class, name, count, town)
.as((Path) countries.stateJoin));
OR
childGroup.add(Projections.bean(State.class, name, count, list(town)).as((Path) countries.stateJoin));
query.select(fields);
query.where();
final Map<? extends Number, ? extends Object> t =
(Map<? extends Number, ? extends Object>)
query
.limit(pageRequest.getPageSize())
.offset(pageRequest.getOffset())
.distinct()
.transform(
GroupBy.groupBy(groupByPath)
.as(Projections.bean(Countris.class, childGroup.toArray(new Expression[0]))));
while executing the above line exactly i am getting always SQLSyntax error as i see the underlying SQL is with
. as towns
Can some one help me how to read the nested collection formed by JPA join?
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
I have a tree-like data structure in my application.
For example, main entity is DraftDoc, it has a child entity DraftEffect. And DraftEffect has its own child entity DraftOffenderCategory.
What is the best strategy for persisting the data to the database?
To collect the whole tree on the front-end side to one big JSON and persist everything at once?
Or to take DraftDoc data (not including related entities) and persist, then take DraftEffect data and persist and so on?
#Entity
#Table(name = "TN_DRAFT_DOCS")
public class DraftDoc implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO, generator = "DRAFTDOC_SEQ")
#SequenceGenerator(name = "DRAFTDOC_SEQ", sequenceName = "NT_DRAFT_DOC_SEQ")
#Column
private Long id;
#Column(name = "ARTICLE_ID")
private Long articleId;
#Column(name = "ARTICLE_VERSION")
private Long articleVersion;
#OneToMany(cascade={CascadeType.ALL},fetch=FetchType.LAZY)
#JoinTable(name = "TN_DRAFT_R_DOC_EFF", joinColumns = { #JoinColumn(name = "doc_id", referencedColumnName = "id") }, inverseJoinColumns = { #JoinColumn(name = "eff_id", referencedColumnName = "id") })
private List<DraftEffect> effects;
...
}
#Entity
#Table(name = "TN_DRAFT_EFFECT")
public class DraftEffect {
#Id
#GeneratedValue(strategy = GenerationType.AUTO, generator = "DRAFT_EFFECT_SEQ")
#SequenceGenerator(name = "DRAFT_EFFECT_SEQ", sequenceName = "NT_DRAFT_EFFECT_SEQ")
#Column
private Long id;
#Column(name = "ARTICLE_ID")
private Long articleId;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "effect")
private List<DraftAffection> affections;
...
}
#Entity
#Table(name = "TN_DRAFT_AFFECTION")
public class DraftAffection implements Serializable {
private static final long serialVersionUID = 3048761786638684368L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO, generator = "DRAFTAFFECTION_SEQ")
#SequenceGenerator(name = "DRAFTAFFECTION_SEQ", sequenceName = "NT_DRAFT_AFFECTION_SEQ")
#Column
private Long id;
#Column(name = "ARTICLE_ID")
private Long articleId;
...
}
#Entity
#Table(name = "EMPLOYEE")
#JsonIgnoreProperties(ignoreUnknown = true)
public class Employee extends AuditModel implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "employee_generator")
#SequenceGenerator(name = "employee_generator", sequenceName = "employee_seq", allocationSize = 50)
#Column(name = "EMPLOYEE_ID")
long employeeId;
#Column(name = "FIRST_NAME")
String firstName;
#Column(name = "LAST_NAME")
String lastName;
#OneToMany(fetch = FetchType.EAGER, mappedBy = "employee", cascade = CascadeType.ALL)
List<Task> tasks;
}
#Entity
#Table(name = "TASK")
#JsonIgnoreProperties(ignoreUnknown = true)
public class Task implements Serializable {
private static final long serialVersionUID = 1L;
public Task() {
super();
}
public Task(String description) {
this.description = description;
}
// details
// type, priority, label, status
// description
// customer address
// state, city, state
// people
// assignee, reporter
// dates
// created, updated
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "task_generator")
#SequenceGenerator(name="task_generator", sequenceName = "task_seq", allocationSize=50)
#Column(name = "TASK_ID")
long taskId;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "EMPLOYEE_ID")
#JsonIgnore
Employee employee;
}
when I get from employee -> task. I am getting an employee object and list of tasks.w
ex:
{
"employeeId":1,
"tasks":[
{
"taskId":1,
"title":"first task"
}
]
}
}
Now the problem I want to get from Task(child) -> employee(parent). I am not getting employee object because I put #JsonIgnore annotation. If I remove the #JsonIgnore I get an infinite loop. Now I want to take employee object from task object, how can I do that?
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;