我正在努力标准化遗留代码库和新开发,以便使用EntityManager进行持久化。但是,为了成功,我需要提供突破本机SQL并手动处理结果的能力。 JPA EntityManager几乎通过以下方式提供此功能:
em.createNativeQuery("select ... from my_table where ...");
但我缺少的是能够做Spring样式的RowMappers。我可以看到有一些机制很接近。我当然可以使用注释,xml等来映射实体,但我需要将代码放入结果集中每一行的处理中,因此这不是一个选项。我可以看到我可以传入SQLResultSetMapping,但是据我所知,这仅支持元数据映射。理想情况下我需要的是:
em.createNativeQuery("select ... from my_table where ...",
new RowMapper {
public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
MyObject o = new MyObject();
o.setMyCustomProperty( rs.get...() );
//...
return b;
}
}
);
是否存在与上述相同的内容?我可以构造一个SQLResultSetMapping,它完全控制上面的映射。
如果没有,我是否可以至少以标准方式获取EM下的数据源,以便我可以使用JdbcTemplate包装它,而不是有两个配置数据源的路径?
DataSource ds = em.getDataSource();
JdbcTemplate t = new JdbcTemplate(ds);
感谢您的帮助。
答案 0 :(得分:2)
实现此目的的一种方法是通过Hibernate会话(假设您正在使用Hibernate)并使用其https://docs.jboss.org/hibernate/core/3.3/api/org/hibernate/transform/ResultTransformer.html。代码应该如下所示,您不需要遍历列表两次:
ResolverStyle
希望这有帮助。
答案 1 :(得分:2)
JPA原生查询结果可以映射到DTO POJO类:
DTO POJO课程
@lombok.Getter
@lombok.AllArgsConstructor
public class MyDto {
private String x;
private Long y;
}
存储库bean:
@Repository
public class MyRepository {
@PersistenceContext private EntityManager em;
static final String MY_SQLMAP = "My-SQL-Mapping";
public List<MyDto> findMy() {
Query query = em.createNativeQuery("select x, y from my_table", MY_SQLMAP);
return query.getResultList();
}
@SqlResultSetMapping(name= MY_SQLMAP, classes = {
@ConstructorResult(targetClass = MyDto.class,
columns = {
@ColumnResult(name="x",type = String.class),
@ColumnResult(name="y",type = Long.class)
}
)
}) @Entity class MyCfgEntity{@Id int id;} // <- walkaround
}
答案 2 :(得分:0)
另一种方法是,如果您不想拥有该解决方案实体,那么将其置于任何有效实体之上,例如
@Entity
@SqlResult(...)
但是,您将添加与您的实体无关的映射。不幸的是,如果不在实体上,JPA(如JPA 2.1)不会处理SqlResult注释。另一个选择是将它添加到XML ORM映射文件,类似这样。
<?xml version="1.0" encoding="UTF-8" ?>
<entity-mappings xmlns="http://xmlns.jcp.org/xml/ns/persistence/orm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://xmlns.jcp.org/xml/ns/persistence/orm
http://xmlns.jcp.org/xml/ns/persistence/orm_2_1.xsd" version="2.1">
<sql-result-set-mapping name="MySummaryResultMapping">
<constructor-result target-class="model.MySummaryResult">
<column name="x" class="java.lang.String" />
<column name="average" class="java.lang.Double"/>
<column name="foo" class="java.lang.Double"/>
<column name="bar" class="java.lang.Integer"/>
</constructor-result>
</sql-result-set-mapping>
</entity-mappings>
然后在设置实体管理器的Spring环境中,您可以加载映射XML
<bean id="myEntityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="myDataSource"/>
<property name="packagesToScan" value="model"/>
<property name="mappingResources" value="META-INF/persistenceMapping.xml" />
...
</bean>
通过这种方式,您可以执行类似的操作并使用POJO返回查询结果。
@Component
public class MyReportDAO {
@PersistenceContext
private EntityManager entityManager;
public MySummaryResult calculateReportFoo(String foo, LocalDate startDay, LocalDate endDay) {
Query query = entityManager.createNativeQuery("SELECT x, AVG(bar_column) AS average, SUM(foo) AS foo," +
" bar " +
" FROM My_table WHERE FOO= :foo AND bar_DATE BETWEEN :startDay AND :endDay" +
" GROUP BY x,bar", "MySummaryResultMapping");
query.setParameter("foo", foo);
query.setParameter("startDay", startDay);
query.setParameter("endDay", endDay);
return (MySummaryResult) query.getSingleResult();
}
}