【问题标题】:Update an entity with relationships to another entity in spring在春季更新与另一个实体有关系的实体
【发布时间】:2016-12-04 10:37:35
【问题描述】:

我有两个实体,Offre 和 OffreCompetence,它们之间的关系如下:

    @OneToMany(mappedBy="offre",cascade = CascadeType.ALL, fetch = FetchType.EAGER)
        private Collection<OffreCompetence> offreCompetences;

所以每个Offre 实体都有许多OffreCompetence 实体。

假设我有一个“Offre”,如下所示:

    {
        "codeOffre": 144,
        "titre": "Testable 999",
          "offreCompetences": [
    {
      "codeOffreCompetence": 93,
      "niveauRequis": "77",
      "competence": {
        "codeCompetence": 17,
        "titre": "Administrateur Mainframe IBM",
        "activated": true
      }
    },
    {
      "codeOffreCompetence": 94,
      "niveauRequis": "88",
      "competence": {
        "codeCompetence": 18,
        "titre": "Administrateur Autres Systèmes",
        "activated": true
      }
    },
    {
      "codeOffreCompetence": 95,
      "niveauRequis": "99",
      "competence": {
        "codeCompetence": 19,
        "titre": "Concepteur UML, Merise, ...",
        "activated": true
      }
    },
    {
      "codeOffreCompetence": 96,
      "niveauRequis": "88",
      "competence": {
        "codeCompetence": 18,
        "titre": "Administrateur Autres Systèmes",
        "activated": true
      }
    },
    {
      "codeOffreCompetence": 97,
      "niveauRequis": "99",
      "competence": {
        "codeCompetence": 17,
        "titre": "Administrateur Mainframe IBM",
        "activated": true
      }
    }
  ],
        "ville": {
          "codeVille": 2
        },
        "typeContrat": {
          "codeTypeContrat": 3
        }
      }

然后我想更新这个Offre,所以我调用了一个以'Offre'作为参数的put方法,然后这个方法会调用业务代码来更新这个'Offre',这就是更新此实体:

public Offre updateOffre(Offre offre) {

    for(OffreCompetence offreCompetence : offre.getOffreCompetences()) {
        offreCompetence.setOffre(offre);
    }
    return offreRepository.saveAndFlush(offre);
}

所以我会发送这个新的 json,我删除了一些“OffreCompetence”关系并添加了一个新的:

{
    "codeOffre": 144,
    "titre": "Testable 999",
    "offreCompetences": [
      {
        "codeOffreCompetence": 96,
        "niveauRequis": "88",
        "competence": {
          "codeCompetence": 18
        }
      },
      {
        "niveauRequis": "5",
        "competence": {
          "codeCompetence": 17
        }
      }
    ],
    "ville": {
      "codeVille": 2
    },
    "typeContrat": {
      "codeTypeContrat": 3
    }
  }

这里的问题是它将这两个关系作为新关系添加到旧关系中,如您所见,我删除了一个并更新了一个并删除了一个,因此更新后的Offre 应该只包含我的关系已发送。

在设置新关系之前,我考虑过使用一种服务方法删除旧关系,该方法搜索与Offre 的所有关系并删除它们,然后添加我使用Offre 对象发送的关系,但是我希望这能自动完成。

有什么建议吗?

先谢谢了。

编辑:

似乎添加新关系并更新它们是有效的,但删除它不起作用。

【问题讨论】:

  • 你尝试过休眠合并吗?

标签: json spring spring-boot spring-data spring-data-jpa


【解决方案1】:

我能得到最好的分离对象树(您的 JSON Offre 和 OffreCompetence 如下。我的情况是 2 个实体,Order 和 OrderLine,映射方式与您相同。

Order.java

@Entity
@Table(name = "ORDERS")
public class Order implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "ORDER_ID")
    private Long id;

    // ... basic attributes

    // same mapping as in your use case
    @OneToMany(mappedBy = "order", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    private Set<OrderLine> orderLines;

    /* getters and setters */

}

OrderLine.java

@Entity
@Table(name = "ORDER_LINES")
public class OrderLine implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "ORDER_LINE_ID")
    private Long id;

    // ... basic attributes

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "ORDER_ID")
    private Order order;

    /* getters and setters */

    /* equals and hashCode */

}

保存根节点及其子节点是这样完成的:

@Override
public Order findWithReference(String reference) {
    List<Order> list = em.createQuery("SELECT o FROM Order o WHERE o.reference = :reference")
            .setParameter("reference", reference).getResultList();
    if (list.isEmpty()) {
        return null;
    } else if (list.size() == 1) {
        return list.get(0);
    } else {
        throw new IllegalStateException(String.format("The reference '%s' should uniquely identify an order.", reference));
    }
}

@Override
public Order save(Order order) {
    Order managed = findWithReference(order.getReference());
    if (managed == null) {
        em.persist(order);
        return order;
    } else {
        // remove obsolete children and children existing both in detached and managed entity
        for (Iterator<OrderLine> iter = managed.getOrderLines().iterator(); iter.hasNext();) {
            OrderLine managedOrderLine = iter.next();
            if (!order.getOrderLines().contains(managedOrderLine)) {
                iter.remove();
                em.remove(managedOrderLine);
            } else {
                order.getOrderLines().remove(managedOrderLine);
            }
        }
        order.setId(managed.getId());
        return em.merge(order);
    }
}

要获得令人满意的结果,合并的技巧是从托管实体中删除过时的子实体,并从分离的实例中删除已经存在的子实体。为了匹配孩子们,我在OrderLine 中实现了equals 和hashCode,总体上不是那么丑陋的方法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-01-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多