【问题标题】:How to create LinkedList of JPA entities如何创建 JPA 实体的 LinkedList
【发布时间】:2021-01-13 16:47:15
【问题描述】:

我有一个场景,我需要创建一个引用前任列表和后继列表的实体。当收到请求时,我需要创建如下实体:

请求:

{
  // create request details for task2
  "predecessors": ["task1"],
  "successors": ["task3"]
}

我的新实体“task2”现在应该在 DB 中创建如下。

task1 <- task2 -> task3
task1 -> task2
task2 <- task3

在将 task2 保存为 task1 和 next 作为 task3 的同时,我还想将 task1 的下一个更新为 task2,将 task3 的上一个更新为 task1。

我正在努力为上述场景提出 JPA 实体关系。

@Entity
@Table(name = "task")
public class Entity {
  @ManyToMany
  private Set<TaskDatabaseEntity> successors;

  @ManyToMany
  private Set<TaskDatabaseEntity> predecessors;
}

更新:下面是我尝试保存实体的代码。

TaskDatabaseEntity newTaskEntity = taskEntityFromCreateEvent();
List<TaskDatabaseEntity> taskEntities = List.ofAll(new ArrayList<>());
if(domainEvent.getPredecessors() != null && !domainEvent.getPredecessors().isEmpty()) {
  for(TaskEvent event : domainEvent.getPredecessors()) {
    TaskDatabaseEntity entity = taskEntityFromUpdateEvent((TaskUpdate) event, userEntity);
    java.util.Set<TaskDatabaseEntity> suc = entity.getSuccessors() == null?
        new HashSet<>() : entity.getSuccessors();
    suc.add(newTaskEntity);
    taskEntities.append(entity);
    newTaskEntity.getPredecessors().add(entity);
  }
}

if(domainEvent.getSuccessors() != null && !domainEvent.getSuccessors().isEmpty()) {
  for(TaskEvent event : domainEvent.getSuccessors()) {
    taskEntityFromUpdateEvent((TaskUpdate) event, userEntity);
    TaskDatabaseEntity entity = taskEntityFromUpdateEvent((TaskUpdate) event, userEntity);
    java.util.Set<TaskDatabaseEntity> pre = entity.getPredecessors() == null?
        new HashSet<>() : entity.getPredecessors();
    pre.add(newTaskEntity);
    taskEntities.append(entity);
    newTaskEntity.getSuccessors().add(entity);
  }
}
taskEntities.append(newTaskEntity);
List<TaskDatabaseEntity> savedEntities = List.ofAll(taskEntityRepository.saveAll(taskEntities));
newTaskEntity =
    savedEntities.filter(task -> task.getObjectId().equals(domainEvent.getEventId())).toList().get(0);

我正在使用saveAll 一起更新所有实体,但返回的已保存列表为空。我不理解为什么。关于我哪里出错的任何建议?我怀疑我的实体关系,可能是我定义的关系错误。

更新 1: 我试图通过mappedBy 来维持彼此的关系,这样关系就会被隐含,我不需要更新所有实体。

  @ToString.Exclude
  @EqualsAndHashCode.Exclude
  @ManyToMany(mappedBy="predecessors", fetch = FetchType.LAZY)
  private Set<TaskDatabaseEntity> successors;

  @ToString.Exclude
  @EqualsAndHashCode.Exclude
  @ManyToMany(fetch = FetchType.LAZY)
  @JoinTable(schema = "eai", name = "task_ancestors")
  private Set<TaskDatabaseEntity> predecessors;

这是我现在保存它的方式

TaskDatabaseEntity newTaskEntity = taskEntityFromCreateEvent();
if(domainEvent.getPredecessors() != null && !domainEvent.getPredecessors().isEmpty()) {
for(TaskEvent event : domainEvent.getPredecessors()) {
    TaskDatabaseEntity entity = taskEntityFromUpdateEvent((TaskUpdate) event, userEntity);
    newTaskEntity.getPredecessors().add(entity);
    }
}
newTaskEntity = taskEntityRepository.save(newTaskEntity);

我现在可以保存新实体及其前身,并且可以从下表中隐含后继者

【问题讨论】:

  • 你能展示一下你如何保存的代码吗?
  • 更新了保存实体组的代码。每个前任都以他们的继任者作为当前更新,每个继任者都以其前任作为当前更新。

标签: java sql hibernate jpa spring-data-jpa


【解决方案1】:

您在标题中提到LinkedList,但在您的实体中,关系设置为多对多,以便后继者和前任者以“扁平”方式加入您的实体。我根据这种 ManyToMany 方法准备了我的答案,但它很容易应用于更像 LinkedList 实现的 OneToOne 方法。

我认为您缺少级联,并且可能没有正确设置关系的双方。请参阅我的简化和“同步”(您的命名有点混乱)示例:

任务(曾经是实体)

@Entity
@Table(name = "task")
@Getter @Setter
public class Task {
    
    @Id
    @GeneratedValue
    private Long id;
    
    // Sets the persist operation persist also successors
    @ManyToMany(cascade = CascadeType.PERSIST)
    private Set<Task> successors = new HashSet<>();

    // Sets the persist operation persist also predecessors
    @ManyToMany(cascade = CascadeType.PERSIST)
    private Set<Task> predecessors = new HashSet<>();
}

测试一下

private Task task1 = new Task();
private Task task2 = new Task();
private Task task3 = new Task();

@Resource
private TaskRepository repo;

@Test
void test() {
    // assuming history order task1 > task2 > task3

    // You need to handle both sides of relationship before persisting
    // for both lists.
    task2.getPredecessors().add(task1);
    task1.getSuccessors().add(task2);

    task2.getSuccessors().add(task3);
    task3.getPredecessors().add(task2);

    repo.save(task2);
}

【讨论】:

  • 您好,感谢您的快速回答。我试图通过使用 mappedBy 来暗示这种关系。但是,您的方法有效,它有助于解决问题。再次感谢。
猜你喜欢
  • 2021-07-26
  • 2020-01-20
  • 2011-03-04
  • 1970-01-01
  • 2018-04-13
  • 2013-08-30
  • 2019-03-02
  • 2017-04-04
  • 1970-01-01
相关资源
最近更新 更多