This commit is contained in:
@@ -1007,7 +1007,7 @@ public final class DataJDBCSource implements DataSource {
|
||||
final EntityCache<T> cache = info.inner.getCache();
|
||||
if (cache == null) return;
|
||||
for (Serializable id : ids) {
|
||||
T value = find(clazz, false, id);
|
||||
T value = find(clazz, null, false, id);
|
||||
if (value != null) cache.update(value);
|
||||
}
|
||||
}
|
||||
@@ -1064,7 +1064,7 @@ public final class DataJDBCSource implements DataSource {
|
||||
|
||||
@Override
|
||||
public Number getCountDistinctSingleResult(final Class entityClass, String column, FilterBean bean) {
|
||||
return getSingleResult(ReckonType.COUNT, entityClass, true, column, bean);
|
||||
return getSingleResult(ReckonType.DISTINCTCOUNT, entityClass, column, bean);
|
||||
}
|
||||
|
||||
//-----------------------------AVG-----------------------------
|
||||
@@ -1079,14 +1079,21 @@ public final class DataJDBCSource implements DataSource {
|
||||
}
|
||||
|
||||
private <T> Number getSingleResult(final ReckonType type, final Class<T> entityClass, final String column, FilterBean bean) {
|
||||
return getSingleResult(type, entityClass, false, column, bean);
|
||||
}
|
||||
|
||||
private <T> Number getSingleResult(final ReckonType type, final Class<T> entityClass, final boolean distinct, final String column, FilterBean bean) {
|
||||
final Connection conn = createReadSQLConnection();
|
||||
try {
|
||||
final EntityXInfo<T> info = EntityXInfo.load(this, entityClass);
|
||||
final String sql = "SELECT " + type.getReckonColumn((distinct ? "DISTINCT " : "") + "a." + column) + " FROM " + info.getTable() + " a" + createWhereExpression(info, null, bean);
|
||||
final EntityCache<T> cache = info.inner.getCache();
|
||||
if (cache != null && cache.isFullLoaded()) {
|
||||
Predicate<T> filter = null;
|
||||
boolean valid = true;
|
||||
if (bean != null) {
|
||||
FilterInfo finfo = FilterInfo.load(bean.getClass(), this);
|
||||
valid = finfo.isValidCacheJoin();
|
||||
if (valid) filter = finfo.getFilterPredicate(info.inner, bean);
|
||||
}
|
||||
if (valid) return cache.getSingleResult(type, column == null ? null : info.getAttribute(column), filter);
|
||||
}
|
||||
final String sql = "SELECT " + type.getReckonColumn("a." + column) + " FROM " + info.getTable() + " a" + createWhereExpression(info, null, bean);
|
||||
if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(entityClass.getSimpleName() + " single sql=" + sql);
|
||||
final PreparedStatement prestmt = conn.prepareStatement(sql);
|
||||
Number rs = null;
|
||||
@@ -1115,10 +1122,15 @@ public final class DataJDBCSource implements DataSource {
|
||||
*/
|
||||
@Override
|
||||
public <T> T find(Class<T> clazz, Serializable pk) {
|
||||
return find(clazz, true, pk);
|
||||
return find(clazz, null, true, pk);
|
||||
}
|
||||
|
||||
private <T> T find(Class<T> clazz, boolean readcache, Serializable pk) {
|
||||
@Override
|
||||
public <T> T find(Class<T> clazz, final SelectColumn selects, Serializable pk) {
|
||||
return find(clazz, selects, true, pk);
|
||||
}
|
||||
|
||||
private <T> T find(Class<T> clazz, final SelectColumn selects, boolean readcache, Serializable pk) {
|
||||
final EntityXInfo<T> info = EntityXInfo.load(this, clazz);
|
||||
final EntityCache<T> cache = info.inner.getCache();
|
||||
if (readcache && cache != null) {
|
||||
@@ -1134,8 +1146,8 @@ public final class DataJDBCSource implements DataSource {
|
||||
ResultSet set = prestmt.executeQuery();
|
||||
if (set.next()) {
|
||||
rs = info.createInstance();
|
||||
for (Attribute attr : info.query.attributes) {
|
||||
attr.set(rs, set.getObject(attr.field()));
|
||||
for (AttributeX attr : info.query.attributes) {
|
||||
attr.setValue(selects, rs, set);
|
||||
}
|
||||
}
|
||||
set.close();
|
||||
@@ -2033,13 +2045,16 @@ public final class DataJDBCSource implements DataSource {
|
||||
//----------------------------------------------------------------------
|
||||
private static class AttributeX<T, F> implements Attribute<T, F> {
|
||||
|
||||
private final Class clazz;
|
||||
|
||||
private final Class type;
|
||||
|
||||
private final Attribute<T, F> attribute;
|
||||
|
||||
private final String fieldName;
|
||||
|
||||
public AttributeX(Class type, Attribute<T, F> attribute, String fieldname) {
|
||||
public AttributeX(Class clazz, Class type, Attribute<T, F> attribute, String fieldname) {
|
||||
this.clazz = clazz;
|
||||
this.type = type;
|
||||
this.attribute = attribute;
|
||||
this.fieldName = fieldname;
|
||||
@@ -2050,6 +2065,11 @@ public final class DataJDBCSource implements DataSource {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class declaringClass() {
|
||||
return clazz;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String field() {
|
||||
return attribute.field();
|
||||
@@ -2090,6 +2110,7 @@ public final class DataJDBCSource implements DataSource {
|
||||
attribute.set(obj, (F) o);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class EntityXInfo<T> {
|
||||
@@ -2178,7 +2199,7 @@ public final class DataJDBCSource implements DataSource {
|
||||
final Class fieldtype = field.getType();
|
||||
Attribute attribute = inner.getAttribute(fieldname);
|
||||
if (attribute == null) continue;
|
||||
AttributeX attr = new AttributeX(fieldtype, attribute, fieldname);
|
||||
AttributeX attr = new AttributeX(cltmp, fieldtype, attribute, fieldname);
|
||||
if (field.getAnnotation(Id.class) != null) {
|
||||
idfieldtype = fieldtype;
|
||||
GeneratedValue gv = field.getAnnotation(GeneratedValue.class);
|
||||
@@ -2212,7 +2233,7 @@ public final class DataJDBCSource implements DataSource {
|
||||
queryattrs.add(attr);
|
||||
}
|
||||
} while ((cltmp = cltmp.getSuperclass()) != Object.class);
|
||||
AttributeX idxattr = new AttributeX(idfieldtype, inner.getPrimary(), inner.getPrimaryField());
|
||||
AttributeX idxattr = new AttributeX(type, idfieldtype, inner.getPrimary(), inner.getPrimaryField());
|
||||
updateattrs.add(idxattr);
|
||||
this.autoGenerated = auto;
|
||||
this.delete = new ActionInfo("DELETE FROM " + inner.getTable() + wheresql, idxattr);
|
||||
@@ -2299,13 +2320,4 @@ public final class DataJDBCSource implements DataSource {
|
||||
}
|
||||
}
|
||||
|
||||
private static enum ReckonType {
|
||||
|
||||
MAX, MIN, SUM, COUNT, AVG;
|
||||
|
||||
public String getReckonColumn(String col) {
|
||||
if (this == COUNT && !col.contains("DISTINCT")) return this.name() + "(*)";
|
||||
return this.name() + "(" + col + ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,6 +119,11 @@ final class DataJPASource implements DataSource {
|
||||
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T find(Class<T> clazz, SelectColumn selects, Serializable pk) {
|
||||
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||
}
|
||||
|
||||
private static class DataJPAConnection extends DataConnection {
|
||||
|
||||
private final EntityManager manager;
|
||||
|
||||
@@ -263,6 +263,17 @@ public interface DataSource {
|
||||
*/
|
||||
public <T> T find(Class<T> clazz, Serializable pk);
|
||||
|
||||
/**
|
||||
* 根据主键获取对象
|
||||
*
|
||||
* @param <T>
|
||||
* @param clazz
|
||||
* @param selects
|
||||
* @param pk
|
||||
* @return
|
||||
*/
|
||||
public <T> T find(Class<T> clazz, final SelectColumn selects, Serializable pk);
|
||||
|
||||
/**
|
||||
* 根据主键值集合获取对象集合
|
||||
*
|
||||
|
||||
@@ -96,8 +96,73 @@ final class EntityCache<T> {
|
||||
return rs.isPresent() ? (needcopy ? reproduce.copy(this.creator.create(), rs.get()) : rs.get()) : null;
|
||||
}
|
||||
|
||||
public <V> Number getSingleResult(final ReckonType type, final Attribute<T, V> attr, final Predicate<T> filter) {
|
||||
Stream<T> stream = listStream();
|
||||
if (filter != null) stream = stream.filter(filter);
|
||||
switch (type) {
|
||||
case AVG:
|
||||
if (attr.type() == int.class || attr.type() == Integer.class) {
|
||||
return (int) stream.mapToInt(x -> (Integer) attr.get(x)).average().orElse(0);
|
||||
} else if (attr.type() == long.class || attr.type() == Long.class) {
|
||||
return (long) stream.mapToLong(x -> (Long) attr.get(x)).average().orElse(0);
|
||||
} else if (attr.type() == short.class || attr.type() == Short.class) {
|
||||
return (short) stream.mapToInt(x -> ((Short) attr.get(x)).intValue()).average().orElse(0);
|
||||
} else if (attr.type() == float.class || attr.type() == Float.class) {
|
||||
return (float) stream.mapToDouble(x -> ((Float) attr.get(x)).doubleValue()).average().orElse(0);
|
||||
} else if (attr.type() == double.class || attr.type() == Double.class) {
|
||||
return stream.mapToDouble(x -> (Double) attr.get(x)).average().orElse(0);
|
||||
}
|
||||
throw new RuntimeException("getSingleResult error(type:" + type + ", attr.declaringClass: " + attr.declaringClass() + ", attr.field: " + attr.field() + ", attr.type: " + attr.type());
|
||||
case COUNT: return stream.count();
|
||||
case DISTINCTCOUNT: return stream.map(x -> attr.get(x)).distinct().count();
|
||||
|
||||
case MAX:
|
||||
if (attr.type() == int.class || attr.type() == Integer.class) {
|
||||
return stream.mapToInt(x -> (Integer) attr.get(x)).max().orElse(0);
|
||||
} else if (attr.type() == long.class || attr.type() == Long.class) {
|
||||
return stream.mapToLong(x -> (Long) attr.get(x)).max().orElse(0);
|
||||
} else if (attr.type() == short.class || attr.type() == Short.class) {
|
||||
return (short) stream.mapToInt(x -> ((Short) attr.get(x)).intValue()).max().orElse(0);
|
||||
} else if (attr.type() == float.class || attr.type() == Float.class) {
|
||||
return (float) stream.mapToDouble(x -> ((Float) attr.get(x)).doubleValue()).max().orElse(0);
|
||||
} else if (attr.type() == double.class || attr.type() == Double.class) {
|
||||
return stream.mapToDouble(x -> (Double) attr.get(x)).max().orElse(0);
|
||||
}
|
||||
throw new RuntimeException("getSingleResult error(type:" + type + ", attr.declaringClass: " + attr.declaringClass() + ", attr.field: " + attr.field() + ", attr.type: " + attr.type());
|
||||
|
||||
case MIN:
|
||||
if (attr.type() == int.class || attr.type() == Integer.class) {
|
||||
return stream.mapToInt(x -> (Integer) attr.get(x)).min().orElse(0);
|
||||
} else if (attr.type() == long.class || attr.type() == Long.class) {
|
||||
return stream.mapToLong(x -> (Long) attr.get(x)).min().orElse(0);
|
||||
} else if (attr.type() == short.class || attr.type() == Short.class) {
|
||||
return (short) stream.mapToInt(x -> ((Short) attr.get(x)).intValue()).min().orElse(0);
|
||||
} else if (attr.type() == float.class || attr.type() == Float.class) {
|
||||
return (float) stream.mapToDouble(x -> ((Float) attr.get(x)).doubleValue()).min().orElse(0);
|
||||
} else if (attr.type() == double.class || attr.type() == Double.class) {
|
||||
return stream.mapToDouble(x -> (Double) attr.get(x)).min().orElse(0);
|
||||
}
|
||||
throw new RuntimeException("getSingleResult error(type:" + type + ", attr.declaringClass: " + attr.declaringClass() + ", attr.field: " + attr.field() + ", attr.type: " + attr.type());
|
||||
|
||||
case SUM:
|
||||
if (attr.type() == int.class || attr.type() == Integer.class) {
|
||||
return stream.mapToInt(x -> (Integer) attr.get(x)).sum();
|
||||
} else if (attr.type() == long.class || attr.type() == Long.class) {
|
||||
return stream.mapToLong(x -> (Long) attr.get(x)).sum();
|
||||
} else if (attr.type() == short.class || attr.type() == Short.class) {
|
||||
return (short) stream.mapToInt(x -> ((Short) attr.get(x)).intValue()).sum();
|
||||
} else if (attr.type() == float.class || attr.type() == Float.class) {
|
||||
return (float) stream.mapToDouble(x -> ((Float) attr.get(x)).doubleValue()).sum();
|
||||
} else if (attr.type() == double.class || attr.type() == Double.class) {
|
||||
return stream.mapToDouble(x -> (Double) attr.get(x)).sum();
|
||||
}
|
||||
throw new RuntimeException("getSingleResult error(type:" + type + ", attr.declaringClass: " + attr.declaringClass() + ", attr.field: " + attr.field() + ", attr.type: " + attr.type());
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public Collection<T> queryCollection(final boolean set, final SelectColumn selects, final Predicate<T> filter, final Comparator<T> sort) {
|
||||
boolean parallel = isParallel();
|
||||
final boolean parallel = isParallel();
|
||||
final Collection<T> rs = parallel ? (set ? new CopyOnWriteArraySet<>() : new CopyOnWriteArrayList<>()) : (set ? new LinkedHashSet<>() : new ArrayList<>());
|
||||
Stream<T> stream = listStream();
|
||||
if (filter != null) stream = stream.filter(filter);
|
||||
@@ -105,12 +170,14 @@ final class EntityCache<T> {
|
||||
if (selects == null) {
|
||||
stream.forEach(x -> rs.add(needcopy ? reproduce.copy(creator.create(), x) : x));
|
||||
} else {
|
||||
final Map<String, Attribute<T, ?>> attrs = this.attributes;
|
||||
final List<Attribute<T, ?>> attrs = new ArrayList<>();
|
||||
for (Map.Entry<String, Attribute<T, ?>> en : this.attributes.entrySet()) {
|
||||
if (selects.validate(en.getKey())) attrs.add(en.getValue());
|
||||
}
|
||||
stream.forEach(x -> {
|
||||
final T item = creator.create();
|
||||
for (Map.Entry<String, Attribute<T, ?>> en : attrs.entrySet()) {
|
||||
Attribute attr = en.getValue();
|
||||
if (selects.validate(en.getKey())) attr.set(item, attr.get(x));
|
||||
for (Attribute attr : attrs) {
|
||||
attr.set(item, attr.get(x));
|
||||
}
|
||||
rs.add(item);
|
||||
});
|
||||
@@ -142,12 +209,14 @@ final class EntityCache<T> {
|
||||
if (selects == null) {
|
||||
stream.forEach(x -> rs.add(needcopy ? reproduce.copy(creator.create(), x) : x));
|
||||
} else {
|
||||
final Map<String, Attribute<T, ?>> attrs = this.attributes;
|
||||
final List<Attribute<T, ?>> attrs = new ArrayList<>();
|
||||
for (Map.Entry<String, Attribute<T, ?>> en : this.attributes.entrySet()) {
|
||||
if (selects.validate(en.getKey())) attrs.add(en.getValue());
|
||||
}
|
||||
stream.forEach(x -> {
|
||||
final T item = creator.create();
|
||||
for (Map.Entry<String, Attribute<T, ?>> en : attrs.entrySet()) {
|
||||
Attribute attr = en.getValue();
|
||||
if (selects.validate(en.getKey())) attr.set(item, attr.get(x));
|
||||
for (Attribute attr : attrs) {
|
||||
attr.set(item, attr.get(x));
|
||||
}
|
||||
rs.add(item);
|
||||
});
|
||||
|
||||
@@ -92,7 +92,7 @@ public final class EntityInfo<T> {
|
||||
continue;
|
||||
}
|
||||
if (field.getAnnotation(javax.persistence.Id.class) != null) {
|
||||
idAttr0 = attr;
|
||||
if (idAttr0 == null) idAttr0 = attr;
|
||||
primaryType0 = field.getType();
|
||||
primaryName = field.getName();
|
||||
}
|
||||
|
||||
21
src/com/wentch/redkale/source/ReckonType.java
Normal file
21
src/com/wentch/redkale/source/ReckonType.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 com.wentch.redkale.source;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author zhangjx
|
||||
*/
|
||||
public enum ReckonType {
|
||||
|
||||
AVG, COUNT, DISTINCTCOUNT, MAX, MIN, SUM;
|
||||
|
||||
public String getReckonColumn(String col) {
|
||||
if (this == COUNT) return this.name() + "(*)";
|
||||
if (this == DISTINCTCOUNT) return "COUNT(DISTINCT " + col + ")";
|
||||
return this.name() + "(" + col + ")";
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
package com.wentch.redkale.source;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -13,6 +13,10 @@ import java.util.Arrays;
|
||||
*/
|
||||
public final class SelectColumn {
|
||||
|
||||
private String[] startWithColumns;
|
||||
|
||||
private String[] endWithColumns;
|
||||
|
||||
private String[] columns;
|
||||
|
||||
private boolean excludable; //是否排除
|
||||
@@ -20,9 +24,52 @@ public final class SelectColumn {
|
||||
public SelectColumn() {
|
||||
}
|
||||
|
||||
private SelectColumn(String[] columns, boolean excludable) {
|
||||
this.columns = columns;
|
||||
private SelectColumn(String[] columns0, boolean excludable) {
|
||||
this.excludable = excludable;
|
||||
final int len = columns0.length;
|
||||
if (len < 1) return;
|
||||
boolean reg = false;
|
||||
int slen = 0, elen = 0;
|
||||
for (String col : columns0) {
|
||||
if (col.charAt(0) == '^') {
|
||||
slen++;
|
||||
reg = true;
|
||||
} else if (col.charAt(col.length() - 1) == '$') {
|
||||
elen++;
|
||||
reg = true;
|
||||
}
|
||||
}
|
||||
if (reg) {
|
||||
if (slen == len) {
|
||||
this.startWithColumns = new String[len];
|
||||
for (int i = 0; i < len; i++) {
|
||||
this.startWithColumns[i] = columns0[i].substring(1);
|
||||
}
|
||||
} else if (elen == len) {
|
||||
this.endWithColumns = new String[len];
|
||||
for (int i = 0; i < len; i++) {
|
||||
this.endWithColumns[i] = columns0[i].substring(0, columns0[i].length() - 1);
|
||||
}
|
||||
} else {
|
||||
List<String> starts = new ArrayList<>();
|
||||
List<String> ends = new ArrayList<>();
|
||||
List<String> strings = new ArrayList<>();
|
||||
for (String col : columns0) {
|
||||
if (col.charAt(0) == '^') {
|
||||
starts.add(col.substring(1));
|
||||
} else if (col.charAt(col.length() - 1) == '$') {
|
||||
ends.add(col.substring(0, col.length() - 1));
|
||||
} else {
|
||||
strings.add(col);
|
||||
}
|
||||
}
|
||||
if (!starts.isEmpty()) this.startWithColumns = starts.toArray(new String[starts.size()]);
|
||||
if (!ends.isEmpty()) this.endWithColumns = ends.toArray(new String[ends.size()]);
|
||||
if (!strings.isEmpty()) this.columns = strings.toArray(new String[strings.size()]);
|
||||
}
|
||||
} else {
|
||||
this.columns = columns0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -46,8 +93,20 @@ public final class SelectColumn {
|
||||
}
|
||||
|
||||
public boolean validate(String column) {
|
||||
for (String col : this.columns) {
|
||||
if (col.equalsIgnoreCase(column)) return !excludable;
|
||||
if (this.columns != null) {
|
||||
for (String col : this.columns) {
|
||||
if (col.equalsIgnoreCase(column)) return !excludable;
|
||||
}
|
||||
}
|
||||
if (this.startWithColumns != null) {
|
||||
for (String col : this.startWithColumns) {
|
||||
if (column.startsWith(col)) return !excludable;
|
||||
}
|
||||
}
|
||||
if (this.endWithColumns != null) {
|
||||
for (String col : this.endWithColumns) {
|
||||
if (column.endsWith(col)) return !excludable;
|
||||
}
|
||||
}
|
||||
return excludable;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,8 @@ public interface Attribute<T, F> {
|
||||
|
||||
public Class type();
|
||||
|
||||
public Class declaringClass();
|
||||
|
||||
public String field();
|
||||
|
||||
public F get(T obj);
|
||||
@@ -64,7 +66,7 @@ public interface Attribute<T, F> {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T, F> Attribute<T, F> create(Class<T> clazz, String fieldalias0, final Field field0, Method getter0, Method setter0) {
|
||||
public static <T, F> Attribute<T, F> create(final Class<T> clazz, String fieldalias0, final Field field0, Method getter0, Method setter0) {
|
||||
if (fieldalias0.isEmpty()) fieldalias0 = null;
|
||||
int mod = field0 == null ? Modifier.STATIC : field0.getModifiers();
|
||||
if (field0 != null && !Modifier.isStatic(mod) && !Modifier.isPublic(mod)) {
|
||||
@@ -185,6 +187,13 @@ public interface Attribute<T, F> {
|
||||
mv.visitMaxs(1, 1);
|
||||
mv.visitEnd();
|
||||
}
|
||||
{ //declaringClass 方法
|
||||
mv = cw.visitMethod(ACC_PUBLIC, "declaringClass", "()Ljava/lang/Class;", null, null);
|
||||
mv.visitLdcInsn(Type.getType(clazz));
|
||||
mv.visitInsn(ARETURN);
|
||||
mv.visitMaxs(1, 1);
|
||||
mv.visitEnd();
|
||||
}
|
||||
{ //get 方法
|
||||
mv = cw.visitMethod(ACC_PUBLIC, "get", "(" + interDesc + ")" + columnDesc, null, null);
|
||||
int m = 1;
|
||||
|
||||
Reference in New Issue
Block a user