2017-11-17 74 views
7

W moim projekcie mam dwa modele domen. Jednostka nadrzędna i podrzędna. Rodzic odwołuje się do listy uprawnień dziecka. (Post i Komentarze) Oba podmioty mają swoje wiosenne dane JPA CrudRepository<Long, ModelClass>, które są wyeksponowane jako operacje HTTP GET i PUT działające poprawnie i zwracają ładną reprezentację HATEOS tych modeli.Tworzenie nowej jednostki nadrzędnej, która odwołuje się do już istniejącej jednostki podrzędnej w repozytorium danych sprężynowych/HATEOAS

Teraz potrzebuję specjalnego punktu końcowego REST "utwórz nowego rodzica, który odwołuje się do jednego lub więcej już istniejących elementów potomnych". Chciałbym opublikować odniesienia do dzieci jako text/uri liście, że przechodzą w organizmie wniosku jak ten:

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 

Jak zaimplementować ten odpoczynek końcowy? To, co starałem dotąd:

@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) 

} 

Reference/Podobne https://github.com/spring-projects/spring-hateoas/issues/292

+0

Uwaga: wiem, w jaki sposób mogę dodawać elementy do listy dzieci poprzez ekspozycje punktów końcowych wiosenno-hateoas ed przez RepositoryRestResource. Tam mogę utworzyć relację podrzędną parnet poprzez POSTing text/uri-list jak opisano tutaj: https://stackoverflow.com/questions/26259474/how-to-add-elements-in-a-many-to-many-relationship -via-resrings-repositoryrestr? rq = 1 Ale chcę wiedzieć, jak to zrobić we własnym niestandardowym punkcie końcowym odpoczynku. – Robert

+0

Istnieje wiele bardzo podobnych pytań. Ale moim szczególnym przypadkiem jest: chcę utworzyć _NEW_ podmiot nadrzędny, który będzie powiązany z już uprawnieniami dziecka _EXISTING_. – Robert

+0

Jestem trochę zdezorientowany, ale jak dziecko może istnieć przed rodzicem? To tak, jakby utworzyć komentarz do postu, który jeszcze nie istnieje. Zwykle starasz się również unikać czasownika w punkcie końcowym zasobu, ponieważ wywołuje on jakiś punkt zapalny RPC w punkcie końcowym, ale w celu WYREGULOWANIA nie ma znaczenia, czy jest tam, czy nie. –

Odpowiedz

2

Jest jeden związany z tym problem na marginesie, że trzeba także wziąć pod uwagę: Kiedy chcę zapisać rodzica byt, nie chcę w żaden sposób dotykać, zapisywać ani zmieniać istniejącej już istoty podrzędnej. To nie jest takie łatwe w WZP. Ponieważ JPA będzie również (próbować) utrzymywać zależną encję podrzędną. To nie z wyjątkiem:

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

Aby obejść, że trzeba połączyć jednostkę dziecko do transactin WZP save() wywołanie. Jedynym sposobem na znalezienie obu podmiotów w jednej transakcji było utworzenie osobnych usług @Services oznaczonych jako @Transactional. Wydaje się, że to kompletna przesada i nadmierna koncentracja.

Oto mój kod:

PollController.java // punkt końcowy zwyczaj odpoczynku dla entiy RODZICA

@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 // za obsługę transakcji

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