标准比使用JPQL或原始SQL有一些优势,如this answer中所述:type safety;重构友好;减少对字符串的依赖(但仍有一些)。还有一个非常大的缺点:它们不那么可读,而且简直太丑了。是否有(非JPA)Java API用于访问类型安全且可读的关系数据库?
答案 0 :(得分:8)
Timo Westkämper在QueryDSL方面做得很好。该库提供了一个DSL,用于查询不同的持久性提供程序(JPA,MongoDB,Lucene ...)。
但是我经常使用手工制作的解决方案来简化大多数常见的查询(列出限制其某些字段的实体),从而阻止我总是写相同的行。对于大多数复杂的查询,我切换到了不可读和冗长的Criteria API。
答案 1 :(得分:1)
MyBatis是一个第一类持久性框架,支持自定义SQL,存储过程和高级映射。 MyBatis几乎消除了所有JDBC代码和手动设置参数以及检索结果。 MyBatis可以使用简单的XML或Annotations来配置和映射基元,Map接口和Java POJO(Plain Old Java Objects)到数据库记录。
或者,nobeh suggested:jOOQ。
答案 2 :(得分:0)
面对以下实用程序类,我找到了“最终”解决方案,以便更轻松地进行JPA搜索:DynamicQueryBuilder
它提供了元模型,因此您不需要使用连接来描述关系。
按模板搜索pojo !!!只需将值放在实体实例中,它们就会用作标准!
它使用构建器模式,因此它非常易读!
Bank bank = new Bank();
bank.setId(12L);
bank.setAchCode("1213");
bank.setCbeCode("1234");
bank.setStatus(new Lookups(1L));
bank.setAchShortName("121");
List<integer> ids = new ArrayList<integer>();
ids.add(1);
ids.add(2);
ids.add(3);
ids.add(4);
ids.add(5);
List<string> cbeCodes = new ArrayList<string>();
cbeCodes.add("1111");
cbeCodes.add("2222");
DynamicQueryBuilder queryDyncBuilder1 =
new DynamicQueryBuilder.Builder(null).select(bank).withOperType(Operator.OperType.AND).
withAdvancedParam("cbeCode", LIKE, PERCENT_AROUND).withAdvancedParam("id", IN, ids)
.withAdvancedParam("achCode", BETWEEN, cbeCodes).withAdvancedParam("achShortName", GT)
.orderBy("id").orderBy("cbeCode", true).orderBy("status.code", true).build();
System.out.println(queryDyncBuilder1.getQueryString());
如果运行上面的调用,组件将构造以下结果的JPQL查询:
SELECT b
FROM Bank b
WHERE b.status = :status
AND b.cbeCode LIKE :cbeCode
AND b.achShortName > :achShortName
AND b.id IN :id
AND (b.achCode BETWEEN :achCodeFrom AND :achCodeTo)
ORDER BY b.status.code DESC, b.id ASC, b.cbeCode DESC
答案 3 :(得分:0)
我有一个项目,我需要一种明智的方法来动态地将许多复杂的WHERE子句组合在一起,但是我并不需要Hibernate的所有其他功能以及随之而来的复杂性(例如模式管理和模式生成) ,二级缓存,bean映射,对象状态跟踪等)。找到这个问题后,我仍然对替代方案不满意,因此我提出了以下建议:
public class Pred {
private String opcode;
private Pred left;
private Pred right;
private Pred() {
}
public Pred(String opcode, Pred left, Pred right) {
super();
this.opcode = opcode;
this.left = left;
this.right = right;
}
private static Collection<Pred> collect(Pred left, Pred ... right) {
List<Pred> all = new ArrayList<>();
all.add(left);
all.addAll(Arrays.asList(right));
return all;
}
private static Pred lambda(Supplier<String> out) {
return new Pred() {
@Override
public String toSql() {
return "(" + out.get() + ")";
}
};
}
private static Pred quoted(String constantValue) {
return lambda(() -> "'" + constantValue + "'");
}
private static Pred unquoted(String constantValue) {
return lambda(() -> constantValue);
}
public static Pred column(String constantValue) {
return unquoted(constantValue);
}
public static Pred eq(String colname, String val) {
return new Pred("=", column(colname), quoted(val));
}
public static Pred eq(String colname, Number val) {
return new Pred("=", column(colname), unquoted(val.toString()));
}
public static Pred gt(String colname, Number val) {
return new Pred(">", column(colname), unquoted(val.toString()));
}
public static Pred lte(String colname, Number val) {
return new Pred("<=", column(colname), unquoted(val.toString()));
}
public static Pred lt(String colname, Number val) {
return new Pred("<", column(colname), unquoted(val.toString()));
}
public static Pred gte(String colname, Number val) {
return new Pred(">=", column(colname), unquoted(val.toString()));
}
public static Pred and(Collection<Pred> subpreds) {
return lambda(() -> subpreds.stream().map(Pred::toSql).collect(Collectors.joining(" AND ")));
}
public static Pred and(Pred left, Pred ... right ) {
return Pred.and(collect(left,right));
}
public static Pred or(Collection<Pred> subpreds) {
return lambda(() -> subpreds.stream().map(Pred::toSql).collect(Collectors.joining(" OR ")));
}
public static Pred or(Pred left, Pred ... right ) {
return Pred.or(collect(left,right));
}
public static <T extends Number> Pred in(String column, Collection<T> list) {
return lambda(() -> column + " IN (" + list.stream().map(String::valueOf).collect(Collectors.joining(",")) + ")");
}
public String toSql() {
return "(" + left.toSql() + opcode + right.toSql() + ")";
}
}
我建议将其与spring-jdbc结合使用。典型用法:
Pred pred = Pred.and(Pred.gt(VALIDUNTIL, cutoffTime.toEpochMilli()),
Pred.lte(FIRSTSEEN, cutoffTime.toEpochMilli()),
Pred.gt(JSON.ListPrice, minPrice),
Pred.eq(JSON.Status, "Active"));
...
List<...> = jdbcTemplate.query("select ... from ... where " + pred.toSql(), new BeanPropertyRowMapper(...);
使用后果自负-没有防止SQL注入的保护(我的项目中没有要求)。
这是草率编写的,老实说,我希望有人能“借用”它并将其变成一个受欢迎的库:-)