如何创建 JPA 实体的链表。

huangapple go评论80阅读模式
英文:

How to create LinkedList of JPA entities

问题

以下是您提供的内容的翻译部分:

我有一个场景,我需要创建一个实体,该实体引用了前置任务列表和后续任务列表。当收到请求时,我需要创建以下形式的实体:

请求:

{
  // 为task2创建请求详细信息
  "predecessors": ["task1"],
  "successors": ["task3"]
}

我的新实体 "task2" 现在应该在数据库中创建如下:

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

在将任务2保存为前置任务为task1,后续任务为task3时,我还想将任务1的后续任务更新为任务2,将任务3的前置任务更新为任务1。

我在为上述情况设计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);

我现在能够保存新的实体及其前置任务,而后续任务可以从表中隐含地获取,如下图所示:【图片链接】。

英文:

I have a scenario where I need to create an entity which has references to list of predecessors and list of successors. when a request is received, I need to create entity like below:

Request:

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

My new entity "task2" should now be created as below in DB.

task1 &lt;- task2 -&gt; task3
task1 -&gt; task2
task2 &lt;- task3

While saving task2 with previous as task1 and next as task3, I also would like to update task1's next as task2 and task3's previous as task1.

I am struggling to come up with a JPA entity relationship for the above scenario.

@Entity
@Table(name = &quot;task&quot;)
public class Entity {
@ManyToMany
private Set&lt;TaskDatabaseEntity&gt; successors;
@ManyToMany
private Set&lt;TaskDatabaseEntity&gt; predecessors;
}

Update: Below is the the code how I am trying to save the entities.

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

I am updating all the entities together using saveAll, but the return saved list coming as empty. I do not understand why. Any suggestions on where I am going wrong? I am doubting my entity relationship, may be I have defined relation wrong.

Update 1:
I have tried to maintain the relationship of one another through mappedBy, that way the relation will be implied and I dont need to update all the entities.

  @ToString.Exclude
@EqualsAndHashCode.Exclude
@ManyToMany(mappedBy=&quot;predecessors&quot;, fetch = FetchType.LAZY)
private Set&lt;TaskDatabaseEntity&gt; successors;
@ToString.Exclude
@EqualsAndHashCode.Exclude
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(schema = &quot;eai&quot;, name = &quot;task_ancestors&quot;)
private Set&lt;TaskDatabaseEntity&gt; predecessors;

Here is how I am now saving it

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

I am able to now save the new entity with its predecessors and the successors can be implied from the table as below

如何创建 JPA 实体的链表。

答案1

得分: 2

在标题中,您提到了 LinkedList,但在您的实体中,关系设置为 ManyToMany,这样后继节点和前驱节点就以“平铺”的方式加入到实体中。我根据这种 ManyToMany 的方法准备了我的答案,但同样适用于更像是 LinkedList 实现的 OneToOne 方法。

我认为您可能遗漏了级联操作,而且可能没有正确设置关系的双向。请参考我简化并且“同步”的(您的命名有点令人困惑)示例:

Task(原为实体)

@Entity
@Table(name = "task")
@Getter @Setter
public class Task {
    
    @Id
    @GeneratedValue
    private Long id;
    
    // 设置持久化操作也会持久化后继节点
    @ManyToMany(cascade = CascadeType.PERSIST)
    private Set<Task> successors = new HashSet<>();

    // 设置持久化操作也会持久化前驱节点
    @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() {
    // 假设历史顺序为 task1 > task2 > task3

    // 在持久化之前,您需要处理关系的双向
    // 对于两个列表都要处理。
    task2.getPredecessors().add(task1);
    task1.getSuccessors().add(task2);

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

    repo.save(task2);
}
英文:

In title you mention LinkedList but in your entity the relationship is set ManyToMany so that successors and predecessors an joined to your entity in a "flat" manner. I prepared my answer according to this ManyToMany approach but it is easily applied to OneToOne approach that is more like LinkedList implementation.

I think that you are missing cascade and maybe not correctly setting both sides of relationship. See my simplified and "synchronized" (your naming was a bit confusing) example:

Task (was Entity)

@Entity
@Table(name = &quot;task&quot;)
@Getter @Setter
public class Task {
@Id
@GeneratedValue
private Long id;
// Sets the persist operation persist also successors
@ManyToMany(cascade = CascadeType.PERSIST)
private Set&lt;Task&gt; successors = new HashSet&lt;&gt;();
// Sets the persist operation persist also predecessors
@ManyToMany(cascade = CascadeType.PERSIST)
private Set&lt;Task&gt; predecessors = new HashSet&lt;&gt;();
}

Test it

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 &gt; task2 &gt; 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);
}

huangapple
  • 本文由 发表于 2020年9月28日 13:38:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/64096476.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定