From a365d7c59c3edbb40d318a0a1d9f3acb2647df7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=9C=B0=E5=B9=B3=E7=BA=BF?= <22250530@qq.com> Date: Tue, 26 May 2015 17:56:45 +0800 Subject: [PATCH] --- .../wentch/redkale/source/DataJDBCSource.java | 58 ++++++++----- .../wentch/redkale/source/DataJPASource.java | 5 ++ src/com/wentch/redkale/source/DataSource.java | 11 +++ .../wentch/redkale/source/EntityCache.java | 87 +++++++++++++++++-- src/com/wentch/redkale/source/EntityInfo.java | 2 +- src/com/wentch/redkale/source/ReckonType.java | 21 +++++ .../wentch/redkale/source/SelectColumn.java | 69 +++++++++++++-- src/com/wentch/redkale/util/Attribute.java | 11 ++- 8 files changed, 225 insertions(+), 39 deletions(-) create mode 100644 src/com/wentch/redkale/source/ReckonType.java diff --git a/src/com/wentch/redkale/source/DataJDBCSource.java b/src/com/wentch/redkale/source/DataJDBCSource.java index 964c8d819..131cd0453 100644 --- a/src/com/wentch/redkale/source/DataJDBCSource.java +++ b/src/com/wentch/redkale/source/DataJDBCSource.java @@ -1007,7 +1007,7 @@ public final class DataJDBCSource implements DataSource { final EntityCache 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 Number getSingleResult(final ReckonType type, final Class entityClass, final String column, FilterBean bean) { - return getSingleResult(type, entityClass, false, column, bean); - } - - private Number getSingleResult(final ReckonType type, final Class entityClass, final boolean distinct, final String column, FilterBean bean) { final Connection conn = createReadSQLConnection(); try { final EntityXInfo 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 cache = info.inner.getCache(); + if (cache != null && cache.isFullLoaded()) { + Predicate 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 find(Class clazz, Serializable pk) { - return find(clazz, true, pk); + return find(clazz, null, true, pk); } - private T find(Class clazz, boolean readcache, Serializable pk) { + @Override + public T find(Class clazz, final SelectColumn selects, Serializable pk) { + return find(clazz, selects, true, pk); + } + + private T find(Class clazz, final SelectColumn selects, boolean readcache, Serializable pk) { final EntityXInfo info = EntityXInfo.load(this, clazz); final EntityCache 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 implements Attribute { + private final Class clazz; + private final Class type; private final Attribute attribute; private final String fieldName; - public AttributeX(Class type, Attribute attribute, String fieldname) { + public AttributeX(Class clazz, Class type, Attribute 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 { @@ -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 + ")"; - } - } } diff --git a/src/com/wentch/redkale/source/DataJPASource.java b/src/com/wentch/redkale/source/DataJPASource.java index a85cbf288..42a8b56de 100644 --- a/src/com/wentch/redkale/source/DataJPASource.java +++ b/src/com/wentch/redkale/source/DataJPASource.java @@ -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 find(Class 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; diff --git a/src/com/wentch/redkale/source/DataSource.java b/src/com/wentch/redkale/source/DataSource.java index 125376816..ce9194d12 100644 --- a/src/com/wentch/redkale/source/DataSource.java +++ b/src/com/wentch/redkale/source/DataSource.java @@ -263,6 +263,17 @@ public interface DataSource { */ public T find(Class clazz, Serializable pk); + /** + * 根据主键获取对象 + * + * @param + * @param clazz + * @param selects + * @param pk + * @return + */ + public T find(Class clazz, final SelectColumn selects, Serializable pk); + /** * 根据主键值集合获取对象集合 * diff --git a/src/com/wentch/redkale/source/EntityCache.java b/src/com/wentch/redkale/source/EntityCache.java index 06cc82d03..7476d14af 100644 --- a/src/com/wentch/redkale/source/EntityCache.java +++ b/src/com/wentch/redkale/source/EntityCache.java @@ -96,8 +96,73 @@ final class EntityCache { return rs.isPresent() ? (needcopy ? reproduce.copy(this.creator.create(), rs.get()) : rs.get()) : null; } + public Number getSingleResult(final ReckonType type, final Attribute attr, final Predicate filter) { + Stream 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 queryCollection(final boolean set, final SelectColumn selects, final Predicate filter, final Comparator sort) { - boolean parallel = isParallel(); + final boolean parallel = isParallel(); final Collection rs = parallel ? (set ? new CopyOnWriteArraySet<>() : new CopyOnWriteArrayList<>()) : (set ? new LinkedHashSet<>() : new ArrayList<>()); Stream stream = listStream(); if (filter != null) stream = stream.filter(filter); @@ -105,12 +170,14 @@ final class EntityCache { if (selects == null) { stream.forEach(x -> rs.add(needcopy ? reproduce.copy(creator.create(), x) : x)); } else { - final Map> attrs = this.attributes; + final List> attrs = new ArrayList<>(); + for (Map.Entry> en : this.attributes.entrySet()) { + if (selects.validate(en.getKey())) attrs.add(en.getValue()); + } stream.forEach(x -> { final T item = creator.create(); - for (Map.Entry> 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 { if (selects == null) { stream.forEach(x -> rs.add(needcopy ? reproduce.copy(creator.create(), x) : x)); } else { - final Map> attrs = this.attributes; + final List> attrs = new ArrayList<>(); + for (Map.Entry> en : this.attributes.entrySet()) { + if (selects.validate(en.getKey())) attrs.add(en.getValue()); + } stream.forEach(x -> { final T item = creator.create(); - for (Map.Entry> 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); }); diff --git a/src/com/wentch/redkale/source/EntityInfo.java b/src/com/wentch/redkale/source/EntityInfo.java index 15b9c7e67..8fb7328fd 100644 --- a/src/com/wentch/redkale/source/EntityInfo.java +++ b/src/com/wentch/redkale/source/EntityInfo.java @@ -92,7 +92,7 @@ public final class EntityInfo { continue; } if (field.getAnnotation(javax.persistence.Id.class) != null) { - idAttr0 = attr; + if (idAttr0 == null) idAttr0 = attr; primaryType0 = field.getType(); primaryName = field.getName(); } diff --git a/src/com/wentch/redkale/source/ReckonType.java b/src/com/wentch/redkale/source/ReckonType.java new file mode 100644 index 000000000..cd3f62fd9 --- /dev/null +++ b/src/com/wentch/redkale/source/ReckonType.java @@ -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 + ")"; + } +} diff --git a/src/com/wentch/redkale/source/SelectColumn.java b/src/com/wentch/redkale/source/SelectColumn.java index 7e28a584e..4d95061c1 100644 --- a/src/com/wentch/redkale/source/SelectColumn.java +++ b/src/com/wentch/redkale/source/SelectColumn.java @@ -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 starts = new ArrayList<>(); + List ends = new ArrayList<>(); + List 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; } diff --git a/src/com/wentch/redkale/util/Attribute.java b/src/com/wentch/redkale/util/Attribute.java index 3cc383110..0b132f21e 100644 --- a/src/com/wentch/redkale/util/Attribute.java +++ b/src/com/wentch/redkale/util/Attribute.java @@ -21,6 +21,8 @@ public interface Attribute { public Class type(); + public Class declaringClass(); + public String field(); public F get(T obj); @@ -64,7 +66,7 @@ public interface Attribute { } @SuppressWarnings("unchecked") - public static Attribute create(Class clazz, String fieldalias0, final Field field0, Method getter0, Method setter0) { + public static Attribute create(final Class 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 { 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;