我通过Spring Data JPA使用Hibernate并尝试添加计算字段。一个简单的SELECT 1*1
查询可以工作,但是当我添加真正的公式时,Hibernate会完全混淆并生成一个语法无效的查询。
父表:
@Entity
@Table(name = "szallitolevel")
public class Szallitolevel {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
@Min(1)
private Long szam;
@ManyToOne(cascade = CascadeType.REFRESH, fetch = FetchType.EAGER)
@Fetch(FetchMode.JOIN)
private Partner partner;
@Formula("(select sum(xx.mennyiseg) from szallitolevel_sor xx where xx.szallitolevel = id)")
// @Formula("(select 1*1)")
private Long sumMennyiseg;
@OneToMany(mappedBy="szallitolevel", cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval=true)
@Fetch(FetchMode.SUBSELECT)
@Valid
private List<SzallitolevelSor> sorok = new AutoPopulatingList<SzallitolevelSor>(SzallitolevelSor.class);
}
子表:
@Entity
@Table(name = "szallitolevel_sor")
public class SzallitolevelSor {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String nev;
@Min(0)
private Long mennyiseg;
@ManyToOne
private Szallitolevel szallitolevel;
}
生成的查询中甚至没有sum(),并且公式以某种方式找到了WHERE部分:
select
sorok0_.szallitolevel as szallito4_2_1_,
sorok0_.id as id1_3_1_,
sorok0_.id as id1_3_0_,
sorok0_.mennyiseg as mennyise2_3_0_,
sorok0_.nev as nev3_3_0_,
sorok0_.szallitolevel as szallito4_3_0_
from szallitolevel_sor sorok0_
where sorok0_.szallitolevel
in (select szallitole0_.id
from szallitolevel_sor xx
where xx.szallitolevel = szallitole0_.id) as formula0_0_,
partner1_.nev as nev2_1_1_,
partner1_.penz as penz3_1_1_
from szallitolevel szallitole0_
left outer join partner partner1_
on szallitole0_.partner=partner1_.id)
{FAILED after 0 msec}
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'as formula0_0_, partner1_.nev as nev2_1_1_, partner1_.penz as penz3_1_1_ from sz' at line 1
更新:我正在使用JDBCTemplate进行相关查询,请参阅答案
答案 0 :(得分:3)
所以最后我决定尝试将JPA保留为简单的CRUD并允许JDBC转义路径,如果需要超过10分钟才能使JPA工作。使用JDBC解决上述问题需要执行以下步骤:
在其中一个配置类中创建JDBCTemplate bean:
@Bean
public NamedParameterJdbcTemplate jdbcTemplate(DataSource dataSource) {
return new NamedParameterJdbcTemplate(dataSource);
}
设置计算的实体字段瞬态,以便Hibernate忽略它。还要确保有一个吸气剂和一个二传手:
@Entity
@Table(name = "szallitolevel")
public class Szallitolevel {
...
@Transient
private Long sumMennyiseg = 0L;
...
}
自定义JPA存储库(您还可以通过向findAll
提供自定义查询来查看此处针对Hibernate N + 1问题的修复):
public interface SzallitolevelRepoCustom {
List<Szallitolevel> customFindAll();
}
public interface SzallitolevelRepo extends CrudRepository<Szallitolevel, Long>, SzallitolevelRepoCustom {
@Query("select s from Szallitolevel s left join fetch s.partner p")
List<Szallitolevel> findAll();
}
public class SzallitolevelRepoImpl implements SzallitolevelRepoCustom {
private static final String FIND_ALL = "SELECT sz.id, sum(sor.mennyiseg) as sumMennyiseg, partner.nev as 'partner.nev' "
+ "from szallitolevel sz "
+ "left join szallitolevel_sor sor on sor.szallitolevel = sz.id "
+ "left join partner on partner.id = sz.partner "
+ "group by sz.id ";
@Autowired
private NamedParameterJdbcTemplate jdbcTemplate;
@Override
public List<Szallitolevel> customFindAll() {
List<Szallitolevel> result = jdbcTemplate.query(FIND_ALL, new NestedRowMapper<>(Szallitolevel.class));
return result;
}
}
注意SQL中的别名partner.nev
。行映射器将使用它来创建一个空的Partner对象,并仅设置nev
属性。 (如果您需要填充整个对象并且不介意另一个数据库查询,您还可以编写一个Spring转换器,从Long到Partner,从数据库中检索整个对象。)
从here偷走NestedRowMapper
。