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

如何创建引用spring data rest/HATEOAS中已有子实体的新父实体

芮叶秋
2023-03-14

在我的项目中,我有两个领域模型。父实体和子实体。父对象引用子对象的列表。(如帖子和评论)这两个实体都有他们的spring数据JPACrudepository

HTTP GET和PUT操作工作正常,并返回这些模型的良好HATEOS表示。

现在我需要一个特殊的RESTendpoint“创建一个引用一个或多个现有子实体的新父实体”。我想在请求的正文中以文本/uri-list的形式发布对孩子的引用,如下所示:

POST http://localhost:8080/api/v1/createNewParent
HEADER
  Content-Type: text/uri-list
HTTP REQUEST BODY:
   http://localhost:8080/api/v1/Child/4711
   http://localhost:8080/api/v1/Child/4712
   http://localhost:8080/api/v1/Child/4713

如何实现此Rest终结点?这是我目前所尝试的:

 @Autowired
 ParentRepo parentRepo  // Spring Data JPA repository for "parent" entity


 @RequestMapping(value = "/createNewParent", method = RequestMethod.POST)
 public @ResponseBody String createNewParentWithChildren(
    @RequestBody Resources<ChildModel> childList,                         
    PersistentEntityResourceAssembler resourceAssembler
) 
{
   Collection<ChildModel> childrenObjects = childList.getContent()

   // Ok, this gives me the URIs I've posted
   List<Link> links = proposalResource.getLinks();

   // But now how to convert these URIs to domain objects???
   List<ChildModel> listOfChildren = ... ???? ...

   ParentModel newParnet = new ParentModel(listOfChildren)
   parentRepo.save(newParent)

}

参考/相关https://github.com/spring-projects/spring-hateoas/issues/292


共有2个答案

栾钟展
2023-03-14

我也有同样的问题。这个问题有点老,但我找到了另一个解决方案:

事实上,您必须在父级上强制合并,但在创建时调用peris。您可以通过使用空的子列表保存父项,将子项添加到列表中,然后再次保存:

List<ChildModel> listOfChildren = ... ???? ...

ParentModel newParnet = new ParentModel()
parent = parentRepo.save(newParent)
parent.getChilds().addAll(listOfChildren)
parentRepo.save(parent)

要有权合并,您必须对自定义回购进行编码:

public interface PollModelRepositoryCustom {
    public PollModel merge(PollModel poll);
}

及其实施

@Repository
public class PollModelRepositoryCustomImpl implements PollModelRepositoryCustom {
    @PersistenceContext
    private EntityManager entityManager;

    public PollModel merge(PollModel poll) {
        return entityManager.merge(poll);
    }
}

然后,您可以调用:括号回购。(new家长)而不是括号epo.save(new家长)

卢出野
2023-03-14

另一个需要考虑的相关问题是:当我想保存父实体时,我不想以任何方式触摸、保存或更改已经存在的子实体。这在JPA中并不容易。因为JPA还将(尝试)保留从属子实体。此操作失败,但有一个例外:

javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist:

为了避免这种情况,必须将子实体合并到jpasave()调用的transactin中。我发现在一个事务中有两个实体的唯一方法是创建一个单独的@Services,标记为@Transactional。看起来完全是过度的杀戮和过度的冒险。

这是我的密码:

波尔控制器。java//父实体的自定义RESTendpoint

@BasePathAwareController
public class PollController {

@RequestMapping(value = "/createNewPoll", method = RequestMethod.POST)
public @ResponseBody Resource createNewPoll(
    @RequestBody Resource<PollModel> pollResource, 
    PersistentEntityResourceAssembler resourceAssembler
) throws LiquidoRestException
{
  PollModel pollFromRequest = pollResource.getContent();
  LawModel proposalFromRequest = pollFromRequest.getProposals().iterator().next();             // This propsal is a "detached entity". Cannot simply be saved.
  //jpaContext.getEntityManagerByManagedType(PollModel.class).merge(proposal);      // DOES NOT WORK IN SPRING.  Must handle transaction via a seperate PollService class and @Transactional annotation there.

  PollModel createdPoll;
  try {
    createdPoll = pollService.createPoll(proposalFromRequest, resourceAssembler);
  } catch (LiquidoException e) {
    log.warn("Cannot /createNewPoll: "+e.getMessage());
    throw new LiquidoRestException(e.getMessage(), e);
  }

  PersistentEntityResource persistentEntityResource = resourceAssembler.toFullResource(createdPoll);

  log.trace("<= POST /createNewPoll: created Poll "+persistentEntityResource.getLink("self").getHref());

  return persistentEntityResource;   // This nicely returns the HAL representation of the created poll
}

PollService。java//用于事务处理

@Service
public class PollService {

    @Transactional    // This should run inside a transaction (all or nothing)
    public PollModel createPoll(@NotNull LawModel proposal, PersistentEntityResourceAssembler resourceAssembler) throws LiquidoException {
    //===== some functional/business checks on the passed enties (must not be null etc)
    //[...]

    //===== create new Poll with one initial proposal
    log.debug("Will create new poll. InitialProposal (id={}): {}", proposal.getId(), proposal.getTitle());
    PollModel poll = new PollModel();
    LawModel proposalInDB = lawRepo.findByTitle(proposal.getTitle());  // I have to lookup the proposal that I already have

    Set<LawModel> linkedProposals = new HashSet<>();
    linkedProposals.add(proposalInDB);
    poll.setProposals(linkedProposals);

    PollModel savedPoll = pollRepo.save(poll);

    return savedPoll;
}
 类似资料:
  • 我正在尝试为实体创建一个域模型(聚合),该实体包含子实体,并且可以有父实体。我们有实体包。我们可以把包裹分成更小的包裹(儿童)。每个分开的包都有一个父包。域的哪个部分应该包含域逻辑:聚合还是域服务?e、 g.聚合包有一个方法 分包还是原包?解决这个问题的正确方法是什么? 我希望我的域模型被ddd(应用程序和基础设施)的其他部分保持干净和幂等

  • 假设我在前面有一个表单,它有常用的字段和下拉列表。在这些下拉列表中,用户可以选择一个选项,并且每个选项都链接到Spring data JPA中的一个实体; 下拉列表包含一些标签和对应实体的链接作为值。然后,这个值在POST-request中传递给我们希望创建的实体的PagingAndSorting存储库。 假设它是一个具有username的用户,并且他必须与其中一个办公室(也是一个实体)关联: 我

  • 我在代码优先的情况下使用EF,我有这样的模型: 我收到一个客户ID和一个产品ID列表。当产品在数据库中不存在时,我想添加它: 问题是EF试图级联更改并尝试插入一个新的对象,其ID与现有对象相同,因此失败。我如何解决这个问题? 这是插入方法:

  • 我的问题很简单,但找到解决办法却成了一项相当乏味和困难的任务。 我有两个冬眠实体, (或“父”实体)有三个字段, (实体的集合-关系)。 当从的集合中删除时(从对象的集合中删除和通过Dog存储库从数据库中删除),以及更新所有者的地址,然后尝试将更新后的对象保存到数据库中,将引发以下异常: 解决这个问题的一种方法是,在更新集合后,通过使用调用所有者的,获取的新版本,然后更新所有者的地址并将实体保存到

  • 我很好奇,在JPA/Hibernate的父实体中,是否可能有几个相同实体的@manytone关系。 示例:我有银行交易,每笔交易都有一个银行合作伙伴,分别担任债权人和债务人。关键是,我只想编辑一次数据。昵称为“情妇”的银行合作伙伴只有一个:),无论是债权人还是债务人。一旦,它将重命名为妻子,所以我不想单独更改。此外,余额是BankPartners在这两个角色中的所有交易的总和。 @实体公共类事务{