增加ColumnValue功能
This commit is contained in:
@@ -63,6 +63,16 @@ public class DataSourceService implements DataSource, Service, AutoCloseable {
|
||||
source.updateColumn(clazz, column, value, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void updateColumn(final Class<T> clazz, final Serializable id, final ColumnValue... values) {
|
||||
source.updateColumn(clazz, id, values);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void updateColumn(final Class<T> clazz, final FilterNode node, final ColumnValue... values) {
|
||||
source.updateColumn(clazz, node, values);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void updateColumnIncrement(final Class<T> clazz, final Serializable id, final String column, long incvalue) {
|
||||
source.updateColumnIncrement(clazz, id, column, incvalue);
|
||||
|
||||
21
src/org/redkale/source/ColumnExpress.java
Normal file
21
src/org/redkale/source/ColumnExpress.java
Normal file
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package org.redkale.source;
|
||||
|
||||
/**
|
||||
* 函数表达式, 均与SQL定义中的表达式相同
|
||||
*
|
||||
* <p>
|
||||
* 详情见: https://redkale.org
|
||||
*
|
||||
* @author zhangjx
|
||||
*/
|
||||
public enum ColumnExpress {
|
||||
MOV, //直接赋值 col = val
|
||||
INCR, //追加值 col = col + val
|
||||
AND, //与值 col = col & val
|
||||
OR; //或值 col = col | val
|
||||
}
|
||||
67
src/org/redkale/source/ColumnValue.java
Normal file
67
src/org/redkale/source/ColumnValue.java
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package org.redkale.source;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* ColumnValue主要用于多个字段更新的表达式。
|
||||
*
|
||||
* <p>
|
||||
* 详情见: https://redkale.org
|
||||
*
|
||||
* @author zhangjx
|
||||
*/
|
||||
public class ColumnValue {
|
||||
|
||||
private String column;
|
||||
|
||||
private ColumnExpress express;
|
||||
|
||||
private Serializable value;
|
||||
|
||||
public ColumnValue() {
|
||||
}
|
||||
|
||||
public ColumnValue(String column, Serializable value) {
|
||||
this(column, ColumnExpress.MOV, value);
|
||||
}
|
||||
|
||||
public ColumnValue(String column, ColumnExpress express, Serializable value) {
|
||||
this.column = column;
|
||||
this.express = express == null ? ColumnExpress.MOV : express;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getColumn() {
|
||||
return column;
|
||||
}
|
||||
|
||||
public void setColumn(String column) {
|
||||
this.column = column;
|
||||
}
|
||||
|
||||
public ColumnExpress getExpress() {
|
||||
return express;
|
||||
}
|
||||
|
||||
public void setExpress(ColumnExpress express) {
|
||||
this.express = express;
|
||||
}
|
||||
|
||||
public Serializable getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(Serializable value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "{\"column\":\"" + column + "\", \"express\":" + express + ", \"value\":" + ((value instanceof CharSequence) ? ("\"" + value + "\"") : value) + "}";
|
||||
}
|
||||
}
|
||||
@@ -731,6 +731,124 @@ public final class DataDefaultSource implements DataSource, Function<Class, Enti
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据主键值更新对象的多个column对应的值, 必须是Entity Class
|
||||
*
|
||||
* @param <T> Entity类的泛型
|
||||
* @param clazz Entity类
|
||||
* @param id 主键值
|
||||
* @param values 字段值
|
||||
*/
|
||||
@Override
|
||||
public <T> void updateColumn(final Class<T> clazz, final Serializable id, final ColumnValue... values) {
|
||||
final EntityInfo<T> info = loadEntityInfo(clazz);
|
||||
if (info.isVirtualEntity()) {
|
||||
updateColumn(null, info, id, values);
|
||||
return;
|
||||
}
|
||||
Connection conn = createWriteSQLConnection();
|
||||
try {
|
||||
updateColumn(conn, info, id, values);
|
||||
} finally {
|
||||
closeSQLConnection(conn);
|
||||
}
|
||||
}
|
||||
|
||||
private <T> void updateColumn(final Connection conn, final EntityInfo<T> info, final Serializable id, final ColumnValue... values) {
|
||||
if (values == null || values.length < 1) return;
|
||||
try {
|
||||
StringBuilder setsql = new StringBuilder();
|
||||
final List<Attribute<T, Serializable>> attrs = new ArrayList<>();
|
||||
final List<ColumnValue> cols = new ArrayList<>();
|
||||
final boolean virtual = info.isVirtualEntity();
|
||||
for (ColumnValue col : values) {
|
||||
Attribute<T, Serializable> attr = info.getUpdateAttribute(col.getColumn());
|
||||
if (attr == null) continue;
|
||||
attrs.add(attr);
|
||||
cols.add(col);
|
||||
if (!virtual) {
|
||||
if (setsql.length() > 0) setsql.append(", ");
|
||||
setsql.append(info.getSQLColumn(null, col.getColumn())).append(" = ").append(info.formatToString(col.getValue()));
|
||||
}
|
||||
}
|
||||
if (!virtual) {
|
||||
String sql = "UPDATE " + info.getTable(id) + " SET " + setsql + " WHERE " + info.getPrimarySQLColumn() + " = " + FilterNode.formatToString(id);
|
||||
if (debug.get()) logger.finest(info.getType().getSimpleName() + ": " + sql);
|
||||
final Statement stmt = conn.createStatement();
|
||||
stmt.execute(sql);
|
||||
stmt.close();
|
||||
}
|
||||
//---------------------------------------------------
|
||||
final EntityCache<T> cache = info.getCache();
|
||||
if (cache == null) return;
|
||||
T rs = cache.updateColumn(id, attrs, cols);
|
||||
if (cacheListener != null) cacheListener.updateCache(info.getType(), rs);
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据主键值更新对象的多个column对应的值, 必须是Entity Class
|
||||
*
|
||||
* @param <T> Entity类的泛型
|
||||
* @param clazz Entity类
|
||||
* @param node 过滤条件
|
||||
* @param values 字段值
|
||||
*/
|
||||
@Override
|
||||
public <T> void updateColumn(final Class<T> clazz, final FilterNode node, final ColumnValue... values) {
|
||||
final EntityInfo<T> info = loadEntityInfo(clazz);
|
||||
if (info.isVirtualEntity()) {
|
||||
updateColumn(null, info, node, values);
|
||||
return;
|
||||
}
|
||||
Connection conn = createWriteSQLConnection();
|
||||
try {
|
||||
updateColumn(conn, info, node, values);
|
||||
} finally {
|
||||
closeSQLConnection(conn);
|
||||
}
|
||||
}
|
||||
|
||||
private <T> void updateColumn(final Connection conn, final EntityInfo<T> info, final FilterNode node, final ColumnValue... values) {
|
||||
if (values == null || values.length < 1) return;
|
||||
try {
|
||||
StringBuilder setsql = new StringBuilder();
|
||||
final List<Attribute<T, Serializable>> attrs = new ArrayList<>();
|
||||
final List<ColumnValue> cols = new ArrayList<>();
|
||||
final boolean virtual = info.isVirtualEntity();
|
||||
for (ColumnValue col : values) {
|
||||
Attribute<T, Serializable> attr = info.getUpdateAttribute(col.getColumn());
|
||||
if (attr == null) continue;
|
||||
attrs.add(attr);
|
||||
cols.add(col);
|
||||
if (!virtual) {
|
||||
if (setsql.length() > 0) setsql.append(", ");
|
||||
setsql.append(info.getSQLColumn("a", col.getColumn())).append(" = ").append(info.formatToString(col.getValue()));
|
||||
}
|
||||
}
|
||||
if (!virtual) {
|
||||
Map<Class, String> joinTabalis = node.getJoinTabalis();
|
||||
CharSequence join = node.createSQLJoin(this, joinTabalis, info);
|
||||
CharSequence where = node.createSQLExpress(info, joinTabalis);
|
||||
|
||||
String sql = "UPDATE " + info.getTable(node) + " a SET " + setsql + (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where));
|
||||
if (debug.get()) logger.finest(info.getType().getSimpleName() + " update sql=" + sql);
|
||||
final Statement stmt = conn.createStatement();
|
||||
stmt.execute(sql);
|
||||
stmt.close();
|
||||
}
|
||||
//---------------------------------------------------
|
||||
final EntityCache<T> cache = info.getCache();
|
||||
if (cache == null) return;
|
||||
T[] rs = cache.updateColumn(node, attrs, cols);
|
||||
if (cacheListener != null) cacheListener.updateCache(info.getType(), rs);
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据主键值给对象的column对应的值+incvalue, 必须是Entity Class
|
||||
* 等价SQL: UPDATE {clazz} SET {column} = {column} + {incvalue} WHERE {primary} = {id}
|
||||
|
||||
@@ -66,6 +66,10 @@ public interface DataSource {
|
||||
|
||||
public <T> void updateColumn(final Class<T> clazz, final String column, final Serializable value, final FilterNode node);
|
||||
|
||||
public <T> void updateColumn(final Class<T> clazz, final Serializable id, final ColumnValue... values);
|
||||
|
||||
public <T> void updateColumn(final Class<T> clazz, final FilterNode node, final ColumnValue... values);
|
||||
|
||||
public <T> void updateColumnIncrement(final Class<T> clazz, final Serializable id, final String column, long incvalue);
|
||||
|
||||
public <T> void updateColumnAnd(final Class<T> clazz, final Serializable id, final String column, long incvalue);
|
||||
|
||||
@@ -387,15 +387,19 @@ public final class EntityCache<T> {
|
||||
if (value == null) return;
|
||||
T rs = this.map.get(this.primary.get(value));
|
||||
if (rs == null) return;
|
||||
this.chgReproduce.apply(rs, value);
|
||||
synchronized (rs) {
|
||||
this.chgReproduce.apply(rs, value);
|
||||
}
|
||||
}
|
||||
|
||||
public T update(final T value, Collection<Attribute<T, Serializable>> attrs) {
|
||||
if (value == null) return value;
|
||||
T rs = this.map.get(this.primary.get(value));
|
||||
if (rs == null) return rs;
|
||||
for (Attribute attr : attrs) {
|
||||
attr.set(rs, attr.get(value));
|
||||
synchronized (rs) {
|
||||
for (Attribute attr : attrs) {
|
||||
attr.set(rs, attr.get(value));
|
||||
}
|
||||
}
|
||||
return rs;
|
||||
}
|
||||
@@ -404,8 +408,10 @@ public final class EntityCache<T> {
|
||||
if (value == null || node == null) return (T[]) Array.newInstance(type, 0);
|
||||
T[] rms = this.list.stream().filter(node.createPredicate(this)).toArray(len -> (T[]) Array.newInstance(type, len));
|
||||
for (T rs : rms) {
|
||||
for (Attribute attr : attrs) {
|
||||
attr.set(rs, attr.get(value));
|
||||
synchronized (rs) {
|
||||
for (Attribute attr : attrs) {
|
||||
attr.set(rs, attr.get(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
return rms;
|
||||
@@ -427,46 +433,109 @@ public final class EntityCache<T> {
|
||||
return rms;
|
||||
}
|
||||
|
||||
public <V> T updateColumn(final Serializable id, List<Attribute<T, Serializable>> attrs, final List<ColumnValue> values) {
|
||||
if (id == null || attrs == null || attrs.isEmpty()) return null;
|
||||
T rs = this.map.get(id);
|
||||
if (rs == null) return rs;
|
||||
synchronized (rs) {
|
||||
for (int i = 0; i < attrs.size(); i++) {
|
||||
ColumnValue cv = values.get(i);
|
||||
updateColumn(attrs.get(i), rs, cv.getExpress(), cv.getValue());
|
||||
}
|
||||
}
|
||||
return rs;
|
||||
}
|
||||
|
||||
public <V> T[] updateColumn(final FilterNode node, List<Attribute<T, Serializable>> attrs, final List<ColumnValue> values) {
|
||||
if (attrs == null || attrs.isEmpty() || node == null) return (T[]) Array.newInstance(type, 0);
|
||||
T[] rms = this.list.stream().filter(node.createPredicate(this)).toArray(len -> (T[]) Array.newInstance(type, len));
|
||||
for (T rs : rms) {
|
||||
synchronized (rs) {
|
||||
for (int i = 0; i < attrs.size(); i++) {
|
||||
ColumnValue cv = values.get(i);
|
||||
updateColumn(attrs.get(i), rs, cv.getExpress(), cv.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
return rms;
|
||||
}
|
||||
|
||||
public <V> T updateColumnOr(final Serializable id, Attribute<T, V> attr, final long orvalue) {
|
||||
if (id == null) return null;
|
||||
T rs = this.map.get(id);
|
||||
if (rs == null) return rs;
|
||||
Number numb = (Number) attr.get(rs);
|
||||
return updateColumnIncrAndOr(attr, rs, (numb == null) ? orvalue : (numb.longValue() | orvalue));
|
||||
synchronized (rs) {
|
||||
return updateColumn(attr, rs, ColumnExpress.OR, orvalue);
|
||||
}
|
||||
}
|
||||
|
||||
public <V> T updateColumnAnd(final Serializable id, Attribute<T, V> attr, final long andvalue) {
|
||||
if (id == null) return null;
|
||||
T rs = this.map.get(id);
|
||||
if (rs == null) return rs;
|
||||
Number numb = (Number) attr.get(rs);
|
||||
return updateColumnIncrAndOr(attr, rs, (numb == null) ? 0 : (numb.longValue() & andvalue));
|
||||
synchronized (rs) {
|
||||
return updateColumn(attr, rs, ColumnExpress.AND, andvalue);
|
||||
}
|
||||
}
|
||||
|
||||
public <V> T updateColumnIncrement(final Serializable id, Attribute<T, V> attr, final long incvalue) {
|
||||
if (id == null) return null;
|
||||
T rs = this.map.get(id);
|
||||
if (rs == null) return rs;
|
||||
Number numb = (Number) attr.get(rs);
|
||||
return updateColumnIncrAndOr(attr, rs, (numb == null) ? incvalue : (numb.longValue() + incvalue));
|
||||
synchronized (rs) {
|
||||
return updateColumn(attr, rs, ColumnExpress.INCR, incvalue);
|
||||
}
|
||||
}
|
||||
|
||||
private <V> T updateColumnIncrAndOr(Attribute<T, V> attr, final T rs, Number numb) {
|
||||
private <V> T updateColumn(Attribute<T, V> attr, final T rs, final ColumnExpress express, Serializable val) {
|
||||
final Class ft = attr.type();
|
||||
if (ft == int.class || ft == Integer.class) {
|
||||
numb = numb.intValue();
|
||||
} else if (ft == long.class || ft == Long.class) {
|
||||
numb = numb.longValue();
|
||||
} else if (ft == short.class || ft == Short.class) {
|
||||
numb = numb.shortValue();
|
||||
} else if (ft == float.class || ft == Float.class) {
|
||||
numb = numb.floatValue();
|
||||
} else if (ft == double.class || ft == Double.class) {
|
||||
numb = numb.doubleValue();
|
||||
} else if (ft == byte.class || ft == Byte.class) {
|
||||
numb = numb.byteValue();
|
||||
Number numb = null;
|
||||
Serializable newval = null;
|
||||
switch (express) {
|
||||
case INCR:
|
||||
numb = (Number) attr.get(rs);
|
||||
if (numb == null) {
|
||||
numb = (Number) val;
|
||||
} else {
|
||||
numb = numb.longValue() + ((Number) val).longValue();
|
||||
}
|
||||
break;
|
||||
case AND:
|
||||
numb = (Number) attr.get(rs);
|
||||
if (numb == null) {
|
||||
numb = 0;
|
||||
} else {
|
||||
numb = numb.longValue() & ((Number) val).longValue();
|
||||
}
|
||||
break;
|
||||
case OR:
|
||||
numb = (Number) attr.get(rs);
|
||||
if (numb == null) {
|
||||
numb = 0;
|
||||
} else {
|
||||
numb = numb.longValue() | ((Number) val).longValue();
|
||||
}
|
||||
break;
|
||||
case MOV:
|
||||
newval = val;
|
||||
break;
|
||||
}
|
||||
attr.set(rs, (V) numb);
|
||||
if (numb != null) {
|
||||
if (ft == int.class || ft == Integer.class) {
|
||||
newval = numb.intValue();
|
||||
} else if (ft == long.class || ft == Long.class) {
|
||||
newval = numb.longValue();
|
||||
} else if (ft == short.class || ft == Short.class) {
|
||||
newval = numb.shortValue();
|
||||
} else if (ft == float.class || ft == Float.class) {
|
||||
newval = numb.floatValue();
|
||||
} else if (ft == double.class || ft == Double.class) {
|
||||
newval = numb.doubleValue();
|
||||
} else if (ft == byte.class || ft == Byte.class) {
|
||||
newval = numb.byteValue();
|
||||
}
|
||||
}
|
||||
attr.set(rs, (V) newval);
|
||||
return rs;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ import org.redkale.util.Attribute;
|
||||
*
|
||||
* @author zhangjx
|
||||
*/
|
||||
public class FilterNode {
|
||||
public class FilterNode { //FilterNode 不能实现Serializable接口, 否则DataSource很多重载接口会出现冲突
|
||||
|
||||
protected String column;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user