当前位置: 首页 > 知识库问答 >
问题:

设置JPA实体的问题(Spring Boot)

常永怡
2023-03-14

我正在做一个小的测试项目,将数据持久化到一个简单的数据库中。我在设置数据实体时遇到了困惑和问题,需要一些帮助。

我将此开发为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.
}

任务说明。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或数据持久性。

共有1个答案

冀望
2023-03-14

基础知识。所以,就像我说的,没有足够的信息来解决你的问题,因为我没有得到问题。然而,这里有一个2分钟的Spring数据Jpa课程。抽象实体:

@MappedSuperclass
public abstract class AbstractEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private Long id;

    public Long getId() {
        return id;
    }
}

A任务:

@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;  
}

应用程序的一个非常重要的配置。属性。

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

细节:

  1. 除非您需要更改字段名称,否则无需更改字段名称。
  2. 无需初始化List@OneTo多国关系,因为它们实际上只是只读查询字段。mapdBy注释说实体TaskNoteStateChange历史是关系的所有者,并且只有对关系所有者所做的更改才会被持久化。这些实体如您所见被显式创建和持久化。
  3. 默认情况下,当某个LAZY时,您不需要声明它。
  4. 当它是LAZY时,除非您明确告诉JPA这样做,否则不会读取关系,并且默认的JpaRepository接口中没有任何内容可以为您执行此操作。
  5. 因此,当您尝试使用LAZY只读字段而没有显式为其编写查询时,您将得到可怕的LazyLaunalizationException
  6. 对父任务项的引用中可以为空(可以为空)让我感到困惑。这是一个不能为空的外键。请参阅ACID主体。
  7. cascade=CascadeType。ALL如果不在关系的所有者上,则没有任何意义,因此添加它对本示例没有影响。
  8. 是的,您确实可以使用@Join注释并使cascade注释做有趣的事情,但在尝试有趣的东西之前,您最好先掌握基础知识。
  9. 希望这有帮助。
 类似资料:
  • 当我们使用EclipseLink为JPA实体使用静态编织时,我们的应用程序中就会出现异常。 该应用程序是一个web应用程序,使用SpringDataJPA和SpringDataRESTWebMVC提供CRUD功能来更改实体。 当实体类没有通过编织处理时,它就工作了。但一旦我们使用编织实体,我们就会得到: .. 当JSON响应应包含一个实体时,就会发生这种情况。实体非常简单,只有两个属性,没有关联等

  • 我有3个实体- > 课程 组件 时间线课程是一个独立的实体,具有以下属性:课程-(id Integer主键,Course_name) @ Id @ Column(name = " Id ")Integer courseId;@Column(name = "course_name ")字符串course _ name; 接下来是另一个实体模块,模块中的每一行都与一门课程相关,因此模块和课程之间存在一

  • 我有两个实体类它只有一个字段叫做和第二个实体它有两个字段和。数据库结构 我正在创建一个简单的CRUD web-app,但是update方法不是更新实体,而是在DB中插入新值。我检查了一下,当用户点击指定菜单上的更新时,第一个实体的id和它的配料id也会被预先定义。我是spring boot和thymeleaf的新手,不知道当您有一个以上的实体时如何使用JPA。 菜单实体: 配料实体: 控制器(仅更

  • 假设我的数据库中有一个表。每个有许多,每个可能有许多。这将是一个经典的-相关性,因此,如果我想在我的Spring Boot JPA中描述它,我可以如下所示: 设置我的实体并将它们连接起来: 实现我的存储库: 现在让我们假设我想指定每个用户在这个项目中的角色。因此,我将有一个表,它使用以下实体表示来指定不同的角色: 但这与我的用户和项目有什么联系呢?所以我想展示的是,一个用户可以在一个项目中有一个角

  • 问题内容: 我只是在Glassfish 3(持久性提供程序是EclipseLink)上运行的简单Java Web应用程序中了解JPA。到目前为止,我真的很喜欢它(除了netbeans / glassfish交互中的错误),但是我想做到的事情我不确定该怎么做。 我有一个映射到数据库表的实体类(文章)。我正在尝试对返回已计算列的数据库进行查询,但无法弄清楚如何设置Article类的属性,以便在调用查询

  • 问题内容: 我正在开发Spring and Stripes网络应用程序的JPA(Hibernate实现)。我有许多JPA实体,它们具有以下共同的字段,用于审计和查询目的: createdBy-创建实体的人的用户ID。createdOn-创建实体的日期更新By-上一次更新实体的用户的用户ID updateOn- 实体上一次更新的日期 我已经使我的应用程序正常工作,以便在实体持久化时会自动设置crea