15 题: Spring JPA选择特定列

在...创建的问题 Fri, May 27, 2016 12:00 AM

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

例如:
SELECT projectId, projectName FROM projects

    
101
  1. 2014-02-25 07:30:12Z
  2. JPA背后没有寻找特定字段的想法是成本(效率明智)相同,从表格的一行带来一列或所有列。
    2014-09-15 09:30:24Z
  3. @ Desorder - 成本并不总是相同。对于更简单,原始的数据类型来说,这可能不是什么大问题,但我最终在这个页面上的原因是因为我注意到一个简单的“列表文档”查询运行缓慢。该实体有一个BLOB列(需要它用于文件上传/存储)&我怀疑它很慢,因为它将BLOB加载到内存中,即使它们不是列出文档所必需的。
    2015-03-12 20:59:52Z
  4. @ jm0据你记忆,有多少个表有BLOB列?
    2015-03-14 08:06:07Z
  5. @ Desorder它只是一个表,但我正在做一个“列表”功能(多列表列出由给定id创建的所有文档)。我注意到这个问题的唯一原因是因为这个简单的列表查询需要几秒钟,而其他表上的更复杂的查询几乎立即发生。一旦我意识到,我知道随着行的添加会越来越多,因为Spring JPA正在将每个BLOB加载到内存中,即使它们没有被使用。我找到了一个体面的Spring数据解决方案(在下面发布),但我认为我有一个更好的纯JPA注释,如果有效,我会发布tmrw
    2015-03-16 01:26:20Z
  6. 醇>
    15答案                              15 跨度>                         

    您可以在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();
    

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

     
    public List<Project> findAll()
    

    可能值得查看Spring数据 docs

        
    51
    2017-04-19 18:34:17Z
    1. 不需要本机查询。你应该避免使用它们,因为它们破坏了JPQL的优点。见Atals回答。
      2017-01-28 20:26:40Z
    2. 对我来说,我必须使用FIND_PROJECTS属性名称限定第一个属性(value以上)(因此,如果这是我的代码,我将不得不将其写为@Query(value = FIND_PROJECTS, nativeQuery = true),等
      2017-04-17 20:57:30Z
    3. 醇>

    我不喜欢特别的语法(它看起来有点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);
    

    然后当然,你只需要提供一个接受docId&amp;的Document的构造函数。 filename作为构造函数args。

        
    110
    2015-03-12 21:34:23Z
    1. (顺便说一句,我确认,如果导入“文档”,则不需要提供完全限定的类名 - 只是这样,因为它就是这样的在我能找到的唯一样本中完成)
      2015-04-23 14:40:36Z
    2. 这应该是接受的答案。它完美无缺,只选择必要的字段。
      2016-07-22 12:13:39Z
    3. 还包含不必要的字段,但值为'null',这些字段会占用内存吗?
      2016-11-21 09:09:51Z
    4. 是的但是很少,以至于在绝大多数情况下尝试围绕这个工程实际上是非常荒谬的 - stackoverflow.com/questions/2430655 /... 你会必须制作没有这些领域的专业轻量级对象。让他们指向同一张桌子?当使用ORM并将它们用于他们的关系时,IMO是不受欢迎的...超级优化可能更多地只是使用一些轻量级查询DSL并直接映射到DTO,&amp;即便如此,我认为不鼓励裁员
      2016-11-21 15:08:35Z
    5. jm0虽然已导入,但没有完全限定的类名,它对我不起作用。它确实成功编译了。
      2018-04-25 13:14:01Z
    6. 醇>

    您可以使用Spring Data JPA中的投影( DOC)。在您的情况下,创建接口:

     
    interface ProjectIdAndName{
        String getId();
        String getName();
    }
    

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

     
    List<ProjectIdAndName> findAll();
    
        
    102
    2016-12-02 14:07:56Z
    1. 这是一个干净的解决方案。它可能有锅炉模板,但接口可以是实体的内部类。让它很干净。
      2017-10-05 22:10:3​​0Z
    2. 这应该是接受的答案。
      2017-10-17 11:30:11Z
    3. 太棒了,只记得不要在你的实体上实现接口,否则它将不起作用
      2017-11-29 05:24:14Z
    4. 投影界面在哪里?在它自己的文件中,还是可以包含在返回完整实体属性的公共接口中?
      2018-01-19 06:25:40Z
    5. 这个解决方案在扩展JpaRepository时不起作用,任何人都知道一个解决方法吗?
      2018-09-06 14:21:47Z
    6. 醇>

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

     
    public interface SchoolRepository extends JpaRepository<School,Integer> {
        @Query("select s.id, s.name from School s")
        List<Object> getSchoolIdAndName();
    }
    
    控制器中的

     
    @Autowired
    private SchoolRepository schoolRepository;
    
    @ResponseBody
    @RequestMapping("getschoolidandname.do")
    public List<Object> getSchool() {
        List<Object> schools = schoolRepository.getSchoolIdAndName();
        return schools;
    }
    
        
    13
    2017-09-10 23:19:05Z
    1. 你应该用mpr所描述的自定义界面替换Object。完美无瑕地工作
      2017-02-21 09:13:35Z
    2. 醇>

    在我的情况下,我创建了一个单独的实体类,没有不需要的字段(仅限于需要的字段)。

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

    e.g。

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

    你可以创建类似的东西:

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

    当你知道要获取的列时(这不会改变),这是有效的。

    如果您需要动态决定列,

    将无效。

        
    12
    2016-12-07 10:50:43Z
    1. 嗨sachin,我有一个疑问,我是否会像上面提到的那样创建实体。当JPA运行时,它将尝试创建名为user的表。哪个实体将使用。
      2018-05-10 06:36:42Z
    2. 从不用JPA创建表,在db中手动创建表,使用JPA将关系世界映射到对象世界。
      2018-05-10 08:33:54Z
    3. 醇>

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

    使用您的问题答案可以是

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

    实体管理器可以是自动连接的,你总是可以使用对象和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));
    

    将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(){....}
    }
    
        
    7
    2014-09-15 08:49:31Z

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

     
    interface PersonRepository extends Repository<Person, UUID> {
    
        <T> Collection<T> findByLastname(String lastname, Class<T> type);
    }
    

    并像这样使用

     
    void someMethod(PersonRepository people) {
    
      Collection<Person> aggregates =
        people.findByLastname("Matthews", Person.class);
    
      Collection<NamesOnly> aggregates =
        people.findByLastname("Matthews", NamesOnly.class);
    }
    
        
    3
    2018-12-28 07:38:43Z
    1. 为什么不返回List&lt; T&gt;而不是收集?!
      2019-03-21 06:39:20Z
    2. @ AbdullahKhan因为结果可能并不总是有订单。
      2019-04-08 21:44:24Z
    3. 醇>
     
    Using Spring Data JPA there is a provision to select specific columns from database
    
    
    ---- In DAOImpl ----
    @Override
        @Transactional
        public List<Employee> getAllEmployee() throws Exception {
        LOGGER.info("Inside getAllEmployee");
        List<Employee> empList = empRepo.getNameAndCityOnly();
        return empList;
        }
    
    ---- In Repo ----
    public interface EmployeeRepository extends CrudRepository<Employee,Integer> {
        @Query("select e.name, e.city from Employee e" )
        List<Employee> getNameAndCityOnly();
    }
    
    It worked 100% in my case.
    Thanks.
    
        
    2
    2017-04-20 07:51:24Z

    可以在本机sql中指定null作为字段值。

     
    @Query(value = "select p.id, p.uid, p.title, null as documentation, p.ptype " +
                " from projects p " +
                "where p.uid = (:uid)" +
                "  and p.ptype = 'P'", nativeQuery = true)
    Project findInfoByUid(@Param("uid") String uid);
    
        
    2
    2017-05-08 19:36:12Z

    您可以在存储库接口类中应用以下代码。

      

    entityname表示您的数据库表名称与项目类似。   而List表示Project是您项目中的Entity类。

     
    @Query(value="select p from #{#entityName} p where p.id=:projectId and p.projectName=:projectName")
    
    List<Project> findAll(@Param("projectId") int projectId, @Param("projectName") String projectName);
    
        
    2
    2017-07-12 10:59:42Z

    您可以使用JPQL:

     
    TypedQuery <Object[]> query = em.createQuery(
      "SELECT p.projectId, p.projectName FROM projects AS p", Object[].class);
    
    List<Object[]> results = query.getResultList();
    

    或者您可以使用原生sql查询。

     
    Query query = em.createNativeQuery("sql statement");
    List<Object[]> results = query.getResultList();
    
        
    1
    2014-02-25 07:39:08Z

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

    如果不使用原生查询,则可以执行以下操作:

     
    public interface ProjectMini {
        String getProjectId();
        String getProjectName();
    }
    
    public interface ProjectRepository extends JpaRepository<Project, String> { 
        @Query("SELECT p FROM Project p")
        List<ProjectMini> findAllProjectsMini();
    }
    

    使用原生查询可以完成同样的操作:

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

    有关详细信息,请查看 docs

        
    1
    2018-12-17 14:25:02Z

    使用原生查询:

     
    Query query = entityManager.createNativeQuery("SELECT projectId, projectName FROM projects");
    List result = query.getResultList();
    
        
    0
    2017-11-04 08:39:53Z

    这里的大多数答案建议使用本机SQL查询的一些变体。但是,使用内置的spring-data jpa,我们也可以实现它:

    您只需在Repository类中使用以下方法签名。

     
    ModelClass findBy$Column_1And$Column_2In(Object $col1Value, Object $col2Value );
    

    根据架构,它可以返回列表或单个实例。此方法可应用于单列或多列,如上所示。

    对于您的示例,它可能类似于:

     
    Project findByProjectIdAndProjectNameIn(long projectId, String projectName);
    

    projectId,projectName

        
    0
    2018-07-04 08:23:34Z
    1. 您缺少这一点,即只选择两列而不是所有实体
      2019-02-13 15:00:21Z
    2. 醇>

    您可以使用@jombie建议的答案,并且:

    • 将接口放在实体类之外的单独文件中;
    • 是否使用原生查询(选择取决于您的需求);
    • 不要为此目的覆盖findAll()方法,而是使用您选择的名称;
    • 记得使用新界面返回List参数化(例如List<SmallProject>)。
    0
    2019-05-18 08:16:25Z
来源放置 这里