好的.. 这是一个非常粗略的解决方案。我仍然不喜欢我必须重复所有字段两次才能获得字段类型 String 或其他类型的事实,但请随意进一步完善它,因为这仍然非常粗糙。此外,您需要在 ps.setObject() 故障保护之前扩展下面的 ps.setSomething() 参数。您还需要预测没有任何条件的查询,例如跳过那些条件对象扫描并直接执行。但我希望你能明白。
public static String addPrefix(String prefix, String field) {
return new StringBuilder(prefix)
.append(Character.toUpperCase(field.charAt(0)))
.append(field.substring(1))
.toString();
}
public static <T> List<T> query(Connection conn, T criteria, String operator) throws SQLException {
List<T> list = null;
Class<?> targetClass = criteria.getClass();
if (targetClass.getAnnotation(Table.class) == null) throw new SQLException("ERROR: Table not defined at entity class " + targetClass.getName());
StringBuilder SQL = new StringBuilder("SELECT * FROM ").append(targetClass.getAnnotation(Table.class).name());
List<Object> parameters = new ArrayList<>();
try {
Field[] fields = targetClass.getDeclaredFields();
for (Field field : fields) {
if (field.getAnnotation(Column.class) == null) continue;
Method m = targetClass.getMethod(addPrefix("get", field.getName()).toString());
Object o = m.invoke(criteria);
if (o == null) continue;
if (parameters.isEmpty()) SQL.append(" WHERE"); else SQL.append(operator);
SQL.append(" ").append(field.getAnnotation(Column.class).name()).append(" = ?");
parameters.add(o);
}
try (Connection connection = IwiPrivate.getInstance().getConnection()) {
try (PreparedStatement ps = connection.prepareStatement(SQL.toString())) {
Integer x = 1;
for (Field field : fields) {
String type = field.getType().getName();
Method m = targetClass.getMethod(addPrefix("get", field.getName()));
Object o = m.invoke(criteria);
if (o == null) continue;
if (type == "java.lang.String") ps.setString(x, (String) parameters.get(x));
else if (type == "java.lang.Integer") ps.setInt(x, (Integer) parameters.get(x));
else ps.setObject(x, parameters.get(x)); //Put more set traps here.
}
try (ResultSet rs = ps.executeQuery();) {
while (rs.next())
list.add((T) Database.mapSingle(rs, targetClass));
}
}
}
} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
Logger.getLogger(QueryExperiment.class.getName()).log(Level.SEVERE, null, ex);
}
return list;
}
现在,要使用它,只需像这样创建您的实体对象
@Table(name = "testTable")
public class Entity {
@Column(name = "id")
private Integer id;
@Column(name = "name")
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
然后把它作为标准
public void testQuery() {
Entity criteria = new Entity();
criteria.setId(7777);
try (Connection connection = yourDatabase.getConnection()) {
List<Entity> assets = QueryTest.query(connection, criteria, "AND");
} catch (SQLException ex) {
Logger.getLogger(IwiPrivateTest.class.getName()).log(Level.SEVERE, null, ex);
}
}
它将创建如下 SQL:
SELECT * FROM testTable WHERE id = ?
并使用 setInt 发送 7777 作为参数
如果您想避免 ORM 并创建简单的查询,我相信这种方法可以正常工作。