Spring JPA选择特定列

use*_*436 119 java jpa spring-data-jpa

我正在使用Spring JPA来执行所有数据库操作.但是我不知道如何从Spring JPA中的表中选择特定的列?

例如:
SELECT projectId, projectName FROM projects

mpr*_*mpr 133

您可以使用Spring Data JPA (doc)中的投影.在您的情况下,创建界面:

interface ProjectIdAndName{
    String getId();
    String getName();
}
Run Code Online (Sandbox Code Playgroud)

并将以下方法添加到您的存储库

List<ProjectIdAndName> findAll();
Run Code Online (Sandbox Code Playgroud)

  • 您不能使用 findAll(); 因为它会与 JPARepositorys 方法发生冲突。您需要使用类似 List&lt;ProjectIdAndName&gt; findAllBy(); 的方法 (9认同)
  • 这是一个干净的解决方案.它可能有锅炉模板,但接口可以是实体的内部类.让它很干净. (7认同)
  • 扩展JpaRepository时此解决方案不起作用,任何人都知道解决方法吗? (6认同)
  • 我在使用 JpaRepository 时没有遇到任何问题,请在存储库类中尝试此方法签名 List&lt;ProjectIdAndName&gt; findAllProjectedBy() 。我还建议在包装方面将投影接口保持在靠近 DTO 的位置​​。IMO 投影接口的行为类似于 DTO。 (4认同)
  • 太棒了,只是记住不要在您的实体上实现该接口,否则它将无法工作 (2认同)
  • 您还需要“as”查询中不映射到投影字段名​​称的任何列,例如,如果表 col 是“event_type”并且投影字段是“eventType”,则查询应该是“select event_type as eventType” ...` (2认同)

jm0*_*jm0 121

我特别喜欢这种语法(它看起来有点像hacky ......)但这是我能找到的最优雅的解决方案(它在JPA存储库类中使用自定义JPQL查询):

@Query("select new com.foo.bar.entity.Document(d.docId, d.filename) from Document d where d.filterCol = ?1")
List<Document> findDocumentsForListing(String filterValue);
Run Code Online (Sandbox Code Playgroud)

当然,您只需要为Document提供一个构造函数,它接受docId&filename作为构造函数args.

  • (顺便说一句,我确认,如果导入"文档",则不需要提供完全限定的类名 - 只需要这样就可以了,因为这是我在能够找到的唯一样本中完成的方式) (8认同)
  • jm0 没有完全限定的类名,它对我不起作用,尽管它是导入的。不过它确实编译成功。 (2认同)

Dur*_*dal 63

您可以nativeQuery = true在类中设置@Query注释,Repository如下所示:

public static final String FIND_PROJECTS = "SELECT projectId, projectName FROM projects";

@Query(value = FIND_PROJECTS, nativeQuery = true)
public List<Object[]> findProjects();
Run Code Online (Sandbox Code Playgroud)

请注意,您必须自己进行映射.除非你真的只需要这两个值,否则使用这样的常规映射查找可能更容易:

public List<Project> findAll()
Run Code Online (Sandbox Code Playgroud)

它也许值得一看Spring数据文档.

  • 不需要本机查询.你应该避免使用它们,因为它们破坏了JPQL的优点.看到Atals回答. (4认同)

小智 15

在我的情况下,我只需要json结果,这对我有用:

public interface SchoolRepository extends JpaRepository<School,Integer> {
    @Query("select s.id, s.name from School s")
    List<Object> getSchoolIdAndName();
}
Run Code Online (Sandbox Code Playgroud)

在控制器中:

@Autowired
private SchoolRepository schoolRepository;

@ResponseBody
@RequestMapping("getschoolidandname.do")
public List<Object> getSchool() {
    List<Object> schools = schoolRepository.getSchoolIdAndName();
    return schools;
}
Run Code Online (Sandbox Code Playgroud)

  • 你应该用 mpr 描述的自定义界面替换`Object`。完美无缺 (2认同)

Sac*_*rma 13

在我的情况下,我创建了一个单独的实体类,没有不需要的字段(只有所需的字段).

将实体映射到同一个表.现在当需要所有列时,我使用旧实体,当只需要一些列时,我使用lite实体.

例如

@Entity
@Table(name = "user")
Class User{
         @Column(name = "id", unique=true, nullable=false)
         int id;
         @Column(name = "name", nullable=false)
         String name;
         @Column(name = "address", nullable=false)
         Address address;
}
Run Code Online (Sandbox Code Playgroud)

您可以创建以下内容:

@Entity
@Table(name = "user")
Class UserLite{
         @Column(name = "id", unique=true, nullable=false)
         int id;
         @Column(name = "name", nullable=false)
         String name;
}
Run Code Online (Sandbox Code Playgroud)

当你知道要获取的列时(这不会改变),这种方法很有效.

如果您需要动态决定列,则无效.

  • 永远不要使用 JPA 创建表,在数据库中手动创建表,使用 JPA 将关系世界映射到对象世界。 (5认同)

jom*_*bie 11

使用较新的 Spring 版本可以执行以下操作:

如果不使用本机查询,可以按如下方式完成:

public interface ProjectMini {
    String getProjectId();
    String getProjectName();
}

public interface ProjectRepository extends JpaRepository<Project, String> { 
    @Query("SELECT p FROM Project p")
    List<ProjectMini> findAllProjectsMini();
}
Run Code Online (Sandbox Code Playgroud)

使用本机查询可以完成如下操作:

public interface ProjectRepository extends JpaRepository<Project, String> { 
    @Query(value = "SELECT projectId, projectName FROM project", nativeQuery = true)
    List<ProjectMini> findAllProjectsMini();
}
Run Code Online (Sandbox Code Playgroud)

有关详细信息,请查看文档


Evg*_*sov 8

在我看来,这是一个很好的解决方案:

interface PersonRepository extends Repository<Person, UUID> {

    <T> Collection<T> findByLastname(String lastname, Class<T> type);
}
Run Code Online (Sandbox Code Playgroud)

并像这样使用它

void someMethod(PersonRepository people) {

  Collection<Person> aggregates =
    people.findByLastname("Matthews", Person.class);

  Collection<NamesOnly> aggregates =
    people.findByLastname("Matthews", NamesOnly.class);
}
Run Code Online (Sandbox Code Playgroud)


ksz*_*sze 7

我想简单的方法可能是使用Spring-Data附带的QueryDSL.

使用您的问题答案可以

JPAQuery query = new JPAQuery(entityManager);
List<Tuple> result = query.from(projects).list(project.projectId, project.projectName);
for (Tuple row : result) {
 System.out.println("project ID " + row.get(project.projectId));
 System.out.println("project Name " + row.get(project.projectName)); 
}}
Run Code Online (Sandbox Code Playgroud)

实体管理器可以是Autowired,您始终可以使用对象和clases而无需使用*QL语言.

正如你在链接中看到的那样,最后的选择似乎对我来说更优雅,也就是说,使用DTO来存储结果.适用于您的示例:

JPAQuery query = new JPAQuery(entityManager);
QProject project = QProject.project;
List<ProjectDTO> dtos = query.from(project).list(new QProjectDTO(project.projectId, project.projectName));
Run Code Online (Sandbox Code Playgroud)

将ProjectDTO定义为:

class ProjectDTO {

 private long id;
 private String name;
 @QueryProjection
 public ProjectDTO(long projectId, String projectName){
   this.id = projectId;
   this.name = projectName;
 }
 public String getProjectId(){ ... }
 public String getProjectName(){....}
}
Run Code Online (Sandbox Code Playgroud)


小智 6

使用 Spring Data JPA 可以从数据库中选择特定的列

---- 在 DAOImpl 中----

@Override
    @Transactional
    public List<Employee> getAllEmployee() throws Exception {
    LOGGER.info("Inside getAllEmployee");
    List<Employee> empList = empRepo.getNameAndCityOnly();
    return empList;
    }
Run Code Online (Sandbox Code Playgroud)

---- 在回购中 ----

public interface EmployeeRepository extends CrudRepository<Employee,Integer> {
    @Query("select e.name, e.city from Employee e" )
    List<Employee> getNameAndCityOnly();
}
Run Code Online (Sandbox Code Playgroud)

就我而言,它 100% 有效。谢谢。