[英]Issues with setting up JPA entities (Spring Boot)
我正在做一個小型測試項目,它將數據持久化到一個簡單的數據庫中。 我在設置數據實體時遇到了困惑和問題,可以使用一些幫助。
我正在將其開發為 Spring Boot Java 項目,並使用 JPA 來實現持久性功能。 我對JPA不是很熟悉。
考慮以下模擬模式:
任務:
<simple data fields omitted>
collection of TaskNote items
collection of StateChangeHistory items
reference to a "parent" Task item (can be null)
collection of Task "child" items (may be empty)
任務注:
<simple data fields omitted>
狀態變化歷史:
<simple data fields omitted>
我不確定注釋和構建這些類以促進這種安排的正確方法。 我也不確定這些關系中的一些應該是單向的還是雙向的。 我看過有關建立單向和雙向關系的各種方法的文章,但我仍然感到困惑,不確定何時應使用特定方法。
這是我目前所擁有的:
任務.java:
@Entity
public class Task extends AbstractEntity {
// Simple fields omitted.
@OneToMany(mappedBy = "taskId", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private List<TaskNote> notes = new LinkedList<>();
@OneToMany(mappedBy = "taskId", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private List<StateChangeHistory> stateHistory = new LinkedList<>();
// Have not yet attempted to implement parent and children.
}
TaskNote.java:
@Entity
public class TaskNote extends AbstractEntity {
// Simple fields omitted.
@ManyToOne
@JoinColumn(name = "taskId")
private Task task;
}
StateChangeHistory.java:
@Entity
public class StateChangeHistory extends AbstractEntity {
// Simple fields omitted.
@ManyToOne
@JoinColumn(name = "taskId")
private Task task;
}
抽象實體.java:
@MappedSuperclass
public abstract class AbstractEntity {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
public Long getId() {
return id;
}
// Other items omitted.
}
當我嘗試運行應用程序(此時仍然非常基本)只是為了看看會發生什么時,有大量的控制台輸出,但引起我注意的是以下內容:
...
[WARN ] 2020-11-19 14:06:17.747 [restartedMain] AnnotationConfigServletWebServerApplicationContext - Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Invocation of init method failed; nested exception is org.hibernate.AnnotationException: mappedBy reference an unknown target entity property: com.mycompany.tasks.backend.entity.TaskNote.taskId in com.mycompany.tasks.backend.entity.Task.notes
...
[ERROR] 2020-11-19 14:06:17.794 [restartedMain] SpringApplication - Application run failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Invocation of init method failed; nested exception is org.hibernate.AnnotationException: mappedBy reference an unknown target entity property: com.mycompany.tasks.backend.entity.TaskNote.taskId in com.mycompany.tasks.backend.entity.Task.notes
...
不知道這一切意味着什么,但它與我的實體類有關。 我還想知道我的 POM 文件中是否缺少某些內容,或者是否缺少某種配置。 正如我所說,我一般不熟悉 Java 中的 JPA 或數據持久性。
基礎知識。 所以,就像我說的,你的問題沒有足夠的信息,因為我沒有得到這個問題。 但是,這是一個 2 分鍾的 Spring-Data-Jpa 課程。 一個抽象實體:
@MappedSuperclass
public abstract class AbstractEntity {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
public Long getId() {
return id;
}
}
一個任務:
@Entity
public class Task extends AbstractEntity {
@OneToMany(mappedBy = "task")
List<TaskNote> notes;
@OneToMany(mappedBy = "task")
List<StateChangeHistory> stateHistory;
}
任務筆記
@Entity
public class TaskNote extends AbstractEntity {
@ManyToOne
Task task;
}
狀態變化歷史
@Entity
public class StateChangeHistory extends AbstractEntity {
@ManyToOne
Task task;
}
application.properties 的一個非常重要的配置。
spring.jpa.show-sql=true
一個應用程序:
@Override
public void run(ApplicationArguments args) throws Exception {
save();
Task task = taskRepo.findById(1L).get();
System.out.println("after findById");
System.out.println(task);
System.out.println("after print task");
System.out.println(task.notes);
}
private void save() {
// save ...
Task task = taskRepo.save(new Task());
TaskNote taskNote = new TaskNote();
taskNote.task = task;
taskNoteRepo.save(taskNote);
StateChangeHistory stateChangeHistory = new StateChangeHistory();
stateChangeHistory.task = task;
stateChangeHistoryRepo.save(stateChangeHistory);
}
一個輸出:
2020-11-19 15:06:19.114 INFO 2156 --- [ main] jpatest.JpatestApplication : Started JpatestApplication in 1.798 seconds (JVM running for 2.252)
Hibernate: call next value for hibernate_sequence
Hibernate: insert into task (id) values (?)
Hibernate: call next value for hibernate_sequence
Hibernate: insert into task_note (task_id, id) values (?, ?)
Hibernate: call next value for hibernate_sequence
Hibernate: insert into state_change_history (task_id, id) values (?, ?)
Hibernate: select task0_.id as id1_1_0_ from task task0_ where task0_.id=?
after findById
jpatest.Task@fd53053
after print task
2020-11-19 15:06:19.171 INFO 2156 --- [ main] ConditionEvaluationReportLoggingListener :
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2020-11-19 15:06:19.185 ERROR 2156 --- [ main] o.s.boot.SpringApplication : Application run failed
java.lang.IllegalStateException: Failed to execute ApplicationRunner
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:798) [spring-boot-2.4.0.jar:2.4.0]
at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:785) [spring-boot-2.4.0.jar:2.4.0]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:333) [spring-boot-2.4.0.jar:2.4.0]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1309) [spring-boot-2.4.0.jar:2.4.0]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1298) [spring-boot-2.4.0.jar:2.4.0]
at jpatest.JpatestApplication.main(JpatestApplication.java:13) [classes/:na]
Caused by: org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: jpatest.Task.notes, could not initialize proxy - no Session
細節:
@OneToMany
關系初始化List
,因為它們實際上只是只讀查詢字段。 該mappedBy
注釋說,實體TaskNote
或StateChangeHistory
是owner
的關系,只更改關系的所有者是堅持做。 如您所見,這些實體是顯式創建和持久化的。LAZY
時,您不需要聲明LAZY
。LAZY
時,除非您明確告訴 JPA 這樣做,否則不會讀取該關系,並且默認的JpaRepository
接口中沒有任何內容可以為您執行此操作。LAZY
只讀字段而未明確為其編寫查詢時,您將得到可怕的LazyInitializationException
。can be null
在reference to a "parent" Task item (can be null)
是混淆了我。 這是一個不能為空的外鍵。 請參閱 ACID 主體。cascade = CascadeType.ALL
如果它不在關系的所有者上,則沒有任何意義,因此添加它對本示例沒有影響。@Join
注釋,使cascade
注釋做有趣的事情,但你不敢輕易嘗試的有趣的東西之前獲得基礎知識的手柄要好得多。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.