Model或Record能方便自动生成SQL,将set的值作为SQL参数,只针对主键采用序列的情况进行了单独处理,对于非主键字段采用序列、使用函数等情况只能另外采用手写SQL来处理,这对Model和Record来说算是不小的遗憾。
我的设想是对set过来的序列、函数等值进行下封装,在生成SQL时进行检查,如果满足条件就直接生成到SQL中,不作为参数。重新定义一个OracleDialect如下
/** * 字段值允许不作为参数,生成到Sql中,可以设置序列、数据库函数,甚至子查询 * record.set("seqno","#(to_char(sysdate,'yymmddhh24miss')||lpad(seq.nextval,8,'0'))"); * record.set("createdate","#(sysdate)");<br> * record.set("photo","#(empty_blob())"); */ public class _OracleDialect extends OracleDialect { private static final String INSQL_PREFIX = "#("; private static final String INSQL_SUFFIX = ")"; // 对原有seq.nextval的处理保持兼容 protected boolean isInSql(String value) { return value.startsWith(INSQL_PREFIX) && value.endsWith(INSQL_SUFFIX) || value.endsWith(".nextval"); } protected String getInSqlValue(String value) { return value.endsWith(".nextval")? value: value.substring(INSQL_PREFIX.length(), value.length()-1); } // insert into table (id,name) values(seq.nextval, ?) @Override public void forModelSave(Table table, Map<String, Object> attrs, StringBuilder sql, List<Object> paras) { sql.append("insert into ").append(table.getName()).append('('); StringBuilder temp = new StringBuilder(") values("); // String[] pKeys = table.getPrimaryKey(); int count = 0; for (Entry<String, Object> e: attrs.entrySet()) { String colName = e.getKey(); if (table.hasColumnLabel(colName)) { if (count++ > 0) { sql.append(", "); temp.append(", "); } sql.append(colName); Object value = e.getValue(); // if (value instanceof String && isPrimaryKey(colName, pKeys) && ((String)value).endsWith(".nextval")) { //temp.append(value); if (value instanceof String && isInSql((String)value)) { temp.append(getInSqlValue((String)value)); } else { temp.append('?'); paras.add(value); } } } sql.append(temp.toString()).append(')'); } @Override public void forDbSave(String tableName, String[] pKeys, Record record, StringBuilder sql, List<Object> paras) { tableName = tableName.trim(); trimPrimaryKeys(pKeys); sql.append("insert into "); sql.append(tableName).append('('); StringBuilder temp = new StringBuilder(); temp.append(") values("); int count = 0; for (Entry<String, Object> e: record.getColumns().entrySet()) { String colName = e.getKey(); if (count++ > 0) { sql.append(", "); temp.append(", "); } sql.append(colName); Object value = e.getValue(); // if (value instanceof String && isPrimaryKey(colName, pKeys) && ((String)value).endsWith(".nextval")) { // temp.append(value); if (value instanceof String && isInSql((String)value)) { temp.append(getInSqlValue((String)value)); } else { temp.append('?'); paras.add(value); } } sql.append(temp.toString()).append(')'); } }
ActiveRecordPlugin插件初始化的相关代码
ActiveRecordPlugin arp = new ActiveRecordPlugin(dp); // 配置Oracle方言 arp.setDialect(new _OracleDialect()); // 配置属性名(字段名)大小写不敏感容器工厂 arp.setContainerFactory(new CaseInsensitiveContainerFactory());
还可以改进,比如在Model和Record类里提供封装方法
public Record setInSql(String column, String value) { getColumns().put(column, "#("+value+")"); return this; }