JPA 数据仓库与 SqlResultSetMapping 和本地查询

19

我遇到了以下情况:

我的实体之间存在关联,但是无法使用JPQL语句。我被迫使用原生SQL查询。现在我想将这些结果映射到一个ValueObject中。明确一点,我不想得到一个Object数组列表(List<Object[]>)。我有6个实体,只需要其中的某些列。有人可以给我一个从本地查询实现这种映射的例子吗?

我阅读过的教程

我的代码:

@SqlResultSetMapping(
    name = "findAllDataMapping",
    classes = @ConstructorResult(
            targetClass = MyVO.class,
            columns = {
                    @ColumnResult(name = "userFirstName"),
                    @ColumnResult(name = "userLastName"),
                    @ColumnResult(name = "id"),
                    @ColumnResult(name = "packageName")
            }
    )
)

@NamedNativeQuery(name = "findAllDataMapping",
    query = "SELECT " +
            "    u.first_name as userFirstName, " +
            "    u.last_name as userLastName, " +
            "    i.id as id, " +
            "    s.title as packageName, " +
            "FROM " +
            "    invoice as i " +
            "JOIN user as u on i.user_id=u.id " +
            "LEFT JOIN subscription_package as s on i.subscription_package_id=s.id " +
            "where  u.param1=:param1 and i.param2=:param2" +
)

public class MyVO {
    private String userFirstName;
    private String userLastName;
    private Long id;
    private String packageName;

    public MyVO (String userFName, String userLName,
            Long id, String packageName) {
        this.userFirstName = userFName;
        this.userLastName = userLName;
        this.id = id;
        this.packageName = packageName;
    }

    // getters & setters
}
在我的 jpa-repository 模块中:
public interface MyRepository extends JpaRepository<MyEntity, Long> {
    List<MyVO> findAllOfMyVO(@Param("param1") String param1, @Param("param2") String param2);
}

重点是我不知道在哪里放置这些注释,以便我可以使用这种映射方式。在本地查询中,我无法使用new rs.rado.leo.mypackage.MyVO(...)。我得到了以下错误:

原因是:

org.springframework.data.mapping.PropertyReferenceException: No property findAllOfMyVO found for type MyEntity!

我想我的问题已经很清楚了。如果不清楚,请告诉我,这样我就可以编辑我的问题。

提前感谢!


答案在这里:https://dev59.com/8FgQ5IYBdhLWcg3wXirH#42942353 - Ilya Serbis
一些注解似乎已经过时了。我查看了这个页面以使它们起作用。 https://github.com/eugenp/tutorials/blob/master/persistence-modules/java-jpa/src/main/java/com/baeldung/jpa/sqlresultsetmapping/Employee.java - al gh
4个回答

25
添加缺失的resultClass。
@NamedNativeQuery(name = "findAllDataMapping", resultClass = Entity.class, query="sql")

或者
@NamedNativeQuery(name = "findAllDataMapping", resultClass = MyVO.class, resultSetMapping ="findAllDataMapping" query = "sql")

最后在您的存储库中调用查询。

@Query(nativeQuery = true, name = "findAllDataMapping")
List<MyVO> findAllOfMyVO(@Param("param1") String param1, @Param("param2") String param2);

7
你已经接近成功,但以下几点需要注意:
  1. @SqlResultSetMapping@NamedNativeQuery必须在实体类(Entity)中出现,而不是在值对象(value Object)中。在你的情况下,应该在MyEntity类中,而不是MyVO类中。这应该能解决你遇到的异常。
  2. 进行以上更改后,还需要修改如下内容:
    @NamedNativeQuery(name = "findAllDataMapping", to
    @NamedNativeQuery(name = "MyEntity.findAllDataMapping"
  3. 最后,在某些情况下,你需要在定义@ColumnResult(name = "userFirstName")时进行明确说明。如果它是一个复杂字段,如ZonedDateTime或Boolean,你可能需要明确指定@ColumnResult(name = "date_created", type = ZonedDateTime.class)。
希望对你有所帮助。

这对我没有起作用。 @NamedNativeQuery(name = "MyEntity.findAllDataMapping", 相反,我按照Michelan Arendse的建议做了 @NamedNativeQuery(name = "findAllDataMapping", resultClass = MyVO.class, resultSetMapping ="findAllDataMapping" query = "sql") - al gh

3

您需要将查询标记为查询 :) 并且您需要使用MyVO而不是MyEntity,因为这是您将结果映射到的实体

@Repository
public interface MyRepository extends JpaRepository<MyVO, Long> {

    @Query(nativeQuery = true)
    List<MyVO> findAllOfMyVO(@Param("param1") String param1, @Param("param2") String param2);
}

抱歉,@Urosh T. 我知道你的答案是来自2012年。我正在尝试做类似的事情,但当初始化存储库时,即使我在其中不声明任何方法,我仍然会得到“未管理类型”的错误。你知道为什么吗?谢谢。 - elamas
@elamas,这是今年9月12日的内容 :) “Not a managed type”可能意味着Spring没有扫描您的@Entity类或包含该类的包。 请确保您在application.properties中有一行,其中写着entitymanager.packagesToScan=com.mypack.entity - Urosh T.
嗨@Urosh T, 你是对的,“今年9月12日 :)”。我认为问题在于MyVO类不是一个实体。但是不用担心,我已经找到了其他方法,谢谢。 - elamas
2
@elamas,你是如何解决“不是托管类型”问题的?在我的情况下,MyVO确实不是一个实体,但我仍然想将查询结果映射到MyVO。 - Hannon Queiroz

0

你的@NamedNativeQuery缺少像下面示例中的resultClassresultSetMapping属性:

@NamedNativeQuery(name = "YourEntity.findAllDataMapping",
    resultClass =  MyVO.class ,
    resultSetMapping ="findAllDataMapping",
    query = "SELECT ..."
)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接