如何添加子选择以导致 jpa 查询

时间:2021-03-11 13:29:48

标签: jpa spring-data-jpa

我有一个带有实体 Person 的 Spring Boot 应用程序,其中包含该人的事件列表。

像这样。

public class Person....

private Long id;

private String name;

@ElementCollection(fetch = FetchType.EAGER)
@CollectionTable(name = "person_events", joinColumns = @JoinColumn(name = "person_id"))
private List<String> personEvents = new ArrayList<>();

现在,当我选择时,我想将结果选择到这样的 dto 中。

@Query("""
    select new com.....dtos.PersonDto(p.name, p.events) from Person p
    where p.name = (:name)
""")
  Set<PersonDto> findPersonsByName(String name);

我的存储库失败,因为它无法生成 sql。我怎样才能做到这一点?

1 个答案:

答案 0 :(得分:0)

您正在做的一些事情可以改进,例如:

您可以使用 interface 投影代替构造函数选择

Set<PersonDto> findPersonsByName(String name);

由于您对单个项目进行选择,因此结果将是单个对象。 所以请把它改成

PersonDTO findPersonsByName(String name);

请在下面找到我的完整答案:

package com.example.demo;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.persistence.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

@RestController
@RequestMapping("/person")
public class PersonController {

    private final PersonService personService;

    @Autowired
    public PersonController(PersonService personService) {
        this.personService = personService;
    }

    @GetMapping
    public Iterable<Person> list() {
        return personService.list();
    }

    @PostMapping
    public Person create(@RequestBody Person car) {
        return personService.save(car);
    }

    @GetMapping(path = "/by")
    public PersonDTO getPersonByName(@RequestParam(value = "name") String name) {
        return personService.findPersonByName(name);
    }

}

@Getter
@Setter
@ToString
@Entity
class Person {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;
    private String name;

    @ElementCollection(fetch = FetchType.EAGER)
    @CollectionTable(name = "person_events", joinColumns = @JoinColumn(name = "person_id"))
    private List<String> personEvents = new ArrayList<>();
}

@Service
class PersonService {
    private final PersonRepository personRepository;

    @Autowired
    PersonService(PersonRepository personRepository) {
        this.personRepository = personRepository;
    }

    @Transactional
    public Person save(Person person) {
        return personRepository.save(person);
    }

    @Transactional(readOnly = true)
    public Iterable<Person> list() {
        return personRepository.findAll();
    }

    @Transactional(readOnly = true)
    public PersonDTO findPersonByName(String name) {
        return personRepository.findPersonsByName(name);
    }
}

interface PersonDTO {
    String getName();

    Collection<String> getPersonEvents();
}

@Repository
interface PersonRepository extends JpaRepository<Person, Integer> {
    PersonDTO findPersonsByName(String name);
}