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;
}