This commit is contained in:
@@ -609,17 +609,10 @@ public final class DataDefaultSource implements DataSource, Nameable {
|
||||
//------------------------------------
|
||||
final EntityCache<T> cache = info.getCache();
|
||||
if (cache == null) return;
|
||||
final Attribute<T, Serializable> attr = info.getPrimary();
|
||||
final Serializable[] keys2 = keys;
|
||||
Serializable[] ids = cache.delete((T t) -> {
|
||||
Serializable k = attr.get(t);
|
||||
if (k == null) return false;
|
||||
for (Serializable y : keys2) {
|
||||
if (k.equals(y)) return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
if (cacheListener != null) cacheListener.deleteCache(info.getType(), ids);
|
||||
for (Serializable key : keys) {
|
||||
cache.delete(key);
|
||||
}
|
||||
if (cacheListener != null) cacheListener.deleteCache(info.getType(), keys);
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
@@ -645,7 +638,7 @@ public final class DataDefaultSource implements DataSource, Nameable {
|
||||
delete((Connection) conn.getConnection(), loadEntityInfo(clazz), node);
|
||||
}
|
||||
|
||||
private <T> void delete(final Connection conn, final EntityInfo<T> info, FilterNode node) {
|
||||
private <T> void delete(final Connection conn, final EntityInfo<T> info, final FilterNode node) {
|
||||
try {
|
||||
if (!info.isVirtualEntity()) {
|
||||
String sql = "DELETE FROM " + info.getTable() + node.createFilterSQLExpress(info, null);
|
||||
@@ -658,7 +651,7 @@ public final class DataDefaultSource implements DataSource, Nameable {
|
||||
//------------------------------------
|
||||
final EntityCache<T> cache = info.getCache();
|
||||
if (cache == null) return;
|
||||
Serializable[] ids = cache.delete(node.createFilterPredicate(info, null));
|
||||
Serializable[] ids = cache.delete(node);
|
||||
if (cacheListener != null) cacheListener.deleteCache(info.getType(), ids);
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
@@ -1088,9 +1081,8 @@ public final class DataDefaultSource implements DataSource, Nameable {
|
||||
if (node == null && bean != null) node = loadFilterBeanNode(bean.getClass());
|
||||
final EntityCache<T> cache = info.getCache();
|
||||
if (cache != null && (info.isVirtualEntity() || cache.isFullLoaded())) {
|
||||
Predicate<T> filter = node == null ? null : node.createFilterPredicate(info, bean);
|
||||
if (node == null || node.isJoinAllCached()) {
|
||||
return cache.getNumberResult(reckon, column == null ? null : info.getAttribute(column), filter);
|
||||
return cache.getNumberResult(reckon, column, node, bean);
|
||||
}
|
||||
}
|
||||
final String sql = "SELECT " + reckon.getColumn((column == null || column.isEmpty() ? "*" : ("a." + column))) + " FROM " + info.getTable() + " a"
|
||||
@@ -1135,9 +1127,8 @@ public final class DataDefaultSource implements DataSource, Nameable {
|
||||
if (node == null && bean != null) node = loadFilterBeanNode(bean.getClass());
|
||||
final EntityCache cache = info.getCache();
|
||||
if (cache != null && (info.isVirtualEntity() || cache.isFullLoaded())) {
|
||||
Predicate filter = node == null ? null : node.createFilterPredicate(info, bean);
|
||||
if (node == null || node.isJoinAllCached()) {
|
||||
return cache.getMapResult(info.getAttribute(keyColumn), reckon, reckonColumn == null ? null : info.getAttribute(reckonColumn), filter);
|
||||
return cache.getMapResult(keyColumn, reckon, reckonColumn, node, bean);
|
||||
}
|
||||
}
|
||||
final String sqlkey = info.getSQLColumn(keyColumn);
|
||||
@@ -1442,10 +1433,9 @@ public final class DataDefaultSource implements DataSource, Nameable {
|
||||
final EntityCache<T> cache = info.getCache();
|
||||
if (node == null && bean != null) node = loadFilterBeanNode(bean.getClass());
|
||||
if (readcache && cache != null) {
|
||||
Predicate<T> filter = node == null ? null : node.createFilterPredicate(info, bean);
|
||||
if (node == null || node.isJoinAllCached()) {
|
||||
if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(clazz.getSimpleName() + " cache query predicate = " + filter);
|
||||
Sheet<T> sheet = cache.querySheet(needtotal, selects, filter, flipper, FilterNode.createFilterComparator(info, flipper));
|
||||
if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(clazz.getSimpleName() + " cache query predicate = " + (node == null ? null : node.createFilterPredicate(info, bean)));
|
||||
Sheet<T> sheet = cache.querySheet(needtotal, selects, flipper, node, bean);
|
||||
if (!sheet.isEmpty() || info.isVirtualEntity() || cache.isFullLoaded()) return sheet;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,15 +21,90 @@ import java.util.stream.*;
|
||||
/**
|
||||
*
|
||||
* @author zhangjx
|
||||
* @param <T>
|
||||
*/
|
||||
public final class EntityCache<T> {
|
||||
|
||||
private static class UniqueSequence implements Serializable {
|
||||
|
||||
private final Serializable[] value;
|
||||
|
||||
public UniqueSequence(Serializable[] val) {
|
||||
this.value = val;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Arrays.deepHashCode(this.value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null) return false;
|
||||
if (getClass() != obj.getClass()) return false;
|
||||
final UniqueSequence other = (UniqueSequence) obj;
|
||||
if (value.length != other.value.length) return false;
|
||||
for (int i = 0; i < value.length; i++) {
|
||||
if (!value[i].equals(other.value[i])) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static interface UniqueAttribute<T> extends Predicate<FilterNode> {
|
||||
|
||||
public Serializable getValue(T bean);
|
||||
|
||||
@Override
|
||||
public boolean test(FilterNode node);
|
||||
|
||||
public static <T> UniqueAttribute<T> create(final Attribute<T, Serializable>[] attributes) {
|
||||
if (attributes.length == 1) {
|
||||
final Attribute<T, Serializable> attribute = attributes[0];
|
||||
return new UniqueAttribute<T>() {
|
||||
|
||||
@Override
|
||||
public Serializable getValue(T bean) {
|
||||
return attribute.get(bean);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test(FilterNode node) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return new UniqueAttribute<T>() {
|
||||
|
||||
@Override
|
||||
public Serializable getValue(T bean) {
|
||||
final Serializable[] rs = new Serializable[attributes.length];
|
||||
for (int i = 0; i < rs.length; i++) {
|
||||
rs[i] = attributes[i].get(bean);
|
||||
}
|
||||
return new UniqueSequence(rs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test(FilterNode node) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final Logger logger = Logger.getLogger(EntityCache.class.getName());
|
||||
|
||||
private final ConcurrentHashMap<Serializable, T> map = new ConcurrentHashMap();
|
||||
|
||||
private final CopyOnWriteArrayList<T> list = new CopyOnWriteArrayList(); // CopyOnWriteArrayList 插入慢、查询快; 10w数据插入需要3.2秒; ConcurrentLinkedQueue 插入快、查询慢;10w数据查询需要 0.062秒, 查询慢40%;
|
||||
|
||||
private final HashMap<UniqueAttribute<T>, ConcurrentHashMap<Serializable, Collection<T>>> uniques = new HashMap<>();
|
||||
|
||||
private final Map<String, Comparator<T>> sortComparators = new ConcurrentHashMap<>();
|
||||
|
||||
private final Class<T> type;
|
||||
|
||||
private final boolean needcopy;
|
||||
@@ -38,19 +113,17 @@ public final class EntityCache<T> {
|
||||
|
||||
private final Attribute<T, Serializable> primary;
|
||||
|
||||
//key是field的name
|
||||
private final Map<String, Attribute<T, Serializable>> attributes;
|
||||
|
||||
private final Reproduce<T, T> reproduce;
|
||||
|
||||
private boolean fullloaded;
|
||||
|
||||
public EntityCache(final Class<T> type, Creator<T> creator, Attribute<T, Serializable> primary,
|
||||
Map<String, Attribute<T, Serializable>> attributes) {
|
||||
this.type = type;
|
||||
this.creator = creator;
|
||||
this.primary = primary;
|
||||
this.attributes = attributes;
|
||||
final EntityInfo<T> info;
|
||||
|
||||
public EntityCache(final EntityInfo<T> info) {
|
||||
this.info = info;
|
||||
this.type = info.getType();
|
||||
this.creator = info.getCreator();
|
||||
this.primary = info.primary;
|
||||
this.needcopy = true;
|
||||
this.reproduce = Reproduce.create(type, type, (m) -> {
|
||||
char[] mn = m.getName().substring(3).toCharArray();
|
||||
@@ -62,12 +135,23 @@ public final class EntityCache<T> {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
for (Unique unique : type.getAnnotationsByType(Unique.class)) {
|
||||
final Attribute<T, Serializable>[] attrs = new Attribute[unique.columns().length];
|
||||
for (int i = 0; i < attrs.length; i++) {
|
||||
attrs[i] = info.getAttribute(unique.columns()[i]);
|
||||
}
|
||||
this.uniques.put(UniqueAttribute.create(attrs), new ConcurrentHashMap<>());
|
||||
}
|
||||
}
|
||||
|
||||
public void fullLoad(List<T> all) {
|
||||
if (all == null) return;
|
||||
clear();
|
||||
all.stream().filter(x -> x != null).forEach(x -> this.map.put(this.primary.get(x), x));
|
||||
final HashMap<UniqueAttribute<T>, ConcurrentHashMap<Serializable, Collection<T>>> localUniques = this.uniques;
|
||||
all.stream().filter(x -> x != null).forEach(x -> {
|
||||
this.map.put(this.primary.get(x), x);
|
||||
localUniques.forEach((k, v) -> v.computeIfAbsent(k.getValue(x), (c) -> new ConcurrentLinkedQueue<>()).add(x));
|
||||
});
|
||||
this.list.addAll(all);
|
||||
this.fullloaded = true;
|
||||
}
|
||||
@@ -79,6 +163,7 @@ public final class EntityCache<T> {
|
||||
public void clear() {
|
||||
this.fullloaded = false;
|
||||
this.list.clear();
|
||||
this.uniques.values().forEach(x -> x.clear());
|
||||
this.map.clear();
|
||||
}
|
||||
|
||||
@@ -92,17 +177,14 @@ public final class EntityCache<T> {
|
||||
return rs == null ? null : (needcopy ? reproduce.copy(this.creator.create(), rs) : rs);
|
||||
}
|
||||
|
||||
public T find(final Predicate<T> filter) {
|
||||
if (filter == null) return null;
|
||||
Optional<T> rs = listStream().filter(filter).findFirst();
|
||||
return rs.isPresent() ? (needcopy ? reproduce.copy(this.creator.create(), rs.get()) : rs.get()) : null;
|
||||
}
|
||||
|
||||
public boolean exists(final Predicate<T> filter) {
|
||||
return (filter != null) && listStream().filter(filter).findFirst().isPresent();
|
||||
}
|
||||
|
||||
public <K, V> Map<Serializable, Number> getMapResult(final Attribute<T, K> keyAttr, final Reckon reckon, final Attribute reckonAttr, final Predicate<T> filter) {
|
||||
public <K, V> Map<Serializable, Number> getMapResult(final String keyColumn, final Reckon reckon, final String reckonColumn, final FilterNode node, final FilterBean bean) {
|
||||
final Attribute<T, Serializable> keyAttr = info.getAttribute(keyColumn);
|
||||
final Predicate filter = node == null ? null : node.createFilterPredicate(this.info, bean);
|
||||
final Attribute reckonAttr = reckonColumn == null ? null : info.getAttribute(reckonColumn);
|
||||
Stream<T> stream = listStream();
|
||||
if (filter != null) stream = stream.filter(filter);
|
||||
Collector<T, Map, ?> collector = null;
|
||||
@@ -148,7 +230,9 @@ public final class EntityCache<T> {
|
||||
return rs;
|
||||
}
|
||||
|
||||
public <V> Number getNumberResult(final Reckon reckon, final Attribute<T, V> attr, final Predicate<T> filter) {
|
||||
public <V> Number getNumberResult(final Reckon reckon, final String column, final FilterNode node, final FilterBean bean) {
|
||||
final Attribute<T, Serializable> attr = column == null ? null : info.getAttribute(column);
|
||||
final Predicate<T> filter = node == null ? null : node.createFilterPredicate(this.info, bean);
|
||||
Stream<T> stream = listStream();
|
||||
if (filter != null) stream = stream.filter(filter);
|
||||
switch (reckon) {
|
||||
@@ -213,48 +297,13 @@ public final class EntityCache<T> {
|
||||
return -1;
|
||||
}
|
||||
|
||||
public Set<T> querySet(final SelectColumn selects, final Predicate<T> filter, final Comparator<T> sort) {
|
||||
return (Set<T>) queryCollection(true, selects, filter, sort);
|
||||
public Sheet<T> querySheet(final SelectColumn selects, final Flipper flipper, final FilterNode node, final FilterBean bean) {
|
||||
return querySheet(true, selects, flipper, node, bean);
|
||||
}
|
||||
|
||||
public List<T> queryList(final SelectColumn selects, final Predicate<T> filter, final Comparator<T> sort) {
|
||||
return (List<T>) queryCollection(false, selects, filter, sort);
|
||||
}
|
||||
|
||||
public Collection<T> queryCollection(final boolean set, final SelectColumn selects, final Predicate<T> filter, final Comparator<T> sort) {
|
||||
final Collection<T> rs = set ? new LinkedHashSet<>() : new ArrayList<>();
|
||||
Stream<T> stream = listStream();
|
||||
if (filter != null) stream = stream.filter(filter);
|
||||
if (sort != null) stream = stream.sorted(sort);
|
||||
if (selects == null) {
|
||||
Consumer<? super T> action = x -> rs.add(needcopy ? reproduce.copy(creator.create(), x) : x);
|
||||
if (sort != null) {
|
||||
stream.forEachOrdered(action);
|
||||
} else {
|
||||
stream.forEach(action);
|
||||
}
|
||||
} else {
|
||||
final List<Attribute<T, Serializable>> attrs = new ArrayList<>();
|
||||
for (Map.Entry<String, Attribute<T, Serializable>> en : this.attributes.entrySet()) {
|
||||
if (selects.validate(en.getKey())) attrs.add(en.getValue());
|
||||
}
|
||||
Consumer<? super T> action = x -> {
|
||||
final T item = creator.create();
|
||||
for (Attribute attr : attrs) {
|
||||
attr.set(item, attr.get(x));
|
||||
}
|
||||
rs.add(item);
|
||||
};
|
||||
if (sort != null) {
|
||||
stream.forEachOrdered(action);
|
||||
} else {
|
||||
stream.forEach(action);
|
||||
}
|
||||
}
|
||||
return rs;
|
||||
}
|
||||
|
||||
public Sheet<T> querySheet(final boolean needtotal, final SelectColumn selects, final Predicate<T> filter, final Flipper flipper, final Comparator<T> sort) {
|
||||
public Sheet<T> querySheet(final boolean needtotal, final SelectColumn selects, final Flipper flipper, final FilterNode node, final FilterBean bean) {
|
||||
final Predicate<T> filter = node == null ? null : node.createFilterPredicate(this.info, bean);
|
||||
final Comparator<T> comparator = FilterNode.createFilterComparator(this, flipper);
|
||||
long total = 0;
|
||||
if (needtotal) {
|
||||
Stream<T> stream = listStream();
|
||||
@@ -264,19 +313,19 @@ public final class EntityCache<T> {
|
||||
if (needtotal && total == 0) return new Sheet<>();
|
||||
Stream<T> stream = listStream();
|
||||
if (filter != null) stream = stream.filter(filter);
|
||||
if (sort != null) stream = stream.sorted(sort);
|
||||
if (comparator != null) stream = stream.sorted(comparator);
|
||||
if (flipper != null) stream = stream.skip(flipper.index()).limit(flipper.getSize());
|
||||
final List<T> rs = new ArrayList<>();
|
||||
if (selects == null) {
|
||||
Consumer<? super T> action = x -> rs.add(needcopy ? reproduce.copy(creator.create(), x) : x);
|
||||
if (sort != null) {
|
||||
if (comparator != null) {
|
||||
stream.forEachOrdered(action);
|
||||
} else {
|
||||
stream.forEach(action);
|
||||
}
|
||||
} else {
|
||||
final List<Attribute<T, Serializable>> attrs = new ArrayList<>();
|
||||
for (Map.Entry<String, Attribute<T, Serializable>> en : this.attributes.entrySet()) {
|
||||
for (Map.Entry<String, Attribute<T, Serializable>> en : info.attributes.entrySet()) {
|
||||
if (selects.validate(en.getKey())) attrs.add(en.getValue());
|
||||
}
|
||||
Consumer<? super T> action = x -> {
|
||||
@@ -286,7 +335,7 @@ public final class EntityCache<T> {
|
||||
}
|
||||
rs.add(item);
|
||||
};
|
||||
if (sort != null) {
|
||||
if (comparator != null) {
|
||||
stream.forEachOrdered(action);
|
||||
} else {
|
||||
stream.forEach(action);
|
||||
@@ -298,10 +347,11 @@ public final class EntityCache<T> {
|
||||
|
||||
public void insert(T value) {
|
||||
if (value == null) return;
|
||||
T rs = reproduce.copy(this.creator.create(), value); //确保同一主键值的map与list中的对象必须共用。
|
||||
final T rs = reproduce.copy(this.creator.create(), value); //确保同一主键值的map与list中的对象必须共用。
|
||||
T old = this.map.put(this.primary.get(rs), rs);
|
||||
if (old == null) {
|
||||
this.list.add(rs);
|
||||
this.uniques.forEach((k, v) -> v.computeIfAbsent(k.getValue(rs), (c) -> new ConcurrentLinkedQueue<>()).add(rs));
|
||||
} else {
|
||||
logger.log(Level.WARNING, "cache repeat insert data: " + value);
|
||||
}
|
||||
@@ -309,20 +359,28 @@ public final class EntityCache<T> {
|
||||
|
||||
public void delete(final Serializable id) {
|
||||
if (id == null) return;
|
||||
T rs = this.map.remove(id);
|
||||
final T rs = this.map.remove(id);
|
||||
if (rs != null) this.list.remove(rs);
|
||||
this.uniques.forEach((k, v) -> v.computeIfPresent(k.getValue(rs), (x, u) -> {
|
||||
u.remove(rs);
|
||||
return u;
|
||||
}));
|
||||
}
|
||||
|
||||
public Serializable[] delete(final Predicate<T> filter) {
|
||||
if (filter == null || this.list.isEmpty()) return new Serializable[0];
|
||||
Object[] rms = listStream().filter(filter).toArray();
|
||||
public Serializable[] delete(final FilterNode node) {
|
||||
if (node == null || this.list.isEmpty()) return new Serializable[0];
|
||||
Object[] rms = listStream().filter(node.createFilterPredicate(this.info, null)).toArray();
|
||||
Serializable[] ids = new Serializable[rms.length];
|
||||
int i = -1;
|
||||
for (Object o : rms) {
|
||||
T t = (T) o;
|
||||
final T t = (T) o;
|
||||
ids[++i] = this.primary.get(t);
|
||||
this.map.remove(ids[i]);
|
||||
this.list.remove(t);
|
||||
this.uniques.forEach((k, v) -> v.computeIfPresent(k.getValue(t), (x, u) -> {
|
||||
u.remove(t);
|
||||
return u;
|
||||
}));
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
@@ -396,4 +454,12 @@ public final class EntityCache<T> {
|
||||
private Stream<T> listStream() {
|
||||
return this.list.stream();
|
||||
}
|
||||
|
||||
protected Comparator<T> getSortComparator(String sort) {
|
||||
return this.sortComparators.get(sort);
|
||||
}
|
||||
|
||||
protected void putSortComparator(String sort, Comparator<T> comparator) {
|
||||
this.sortComparators.put(sort, comparator);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ import java.sql.*;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.*;
|
||||
import java.util.logging.*;
|
||||
import javax.persistence.*;
|
||||
|
||||
@@ -38,18 +38,18 @@ public final class EntityInfo<T> {
|
||||
private final Creator<T> creator;
|
||||
|
||||
//主键
|
||||
private final Attribute<T, Serializable> primary;
|
||||
final Attribute<T, Serializable> primary;
|
||||
|
||||
private final EntityCache<T> cache;
|
||||
|
||||
//key是field的name, 不是sql字段。
|
||||
//存放所有与数据库对应的字段, 包括主键
|
||||
final Map<String, Attribute<T, Serializable>> attributes = new HashMap<>();
|
||||
|
||||
//key是field的name, value是Column的别名,即数据库表的字段名
|
||||
//只有field.name 与 Column.name不同才存放在aliasmap里.
|
||||
private final Map<String, String> aliasmap;
|
||||
|
||||
//key是field的name, 不是sql字段。
|
||||
//存放所有与数据库对应的字段, 包括主键
|
||||
private final Map<String, Attribute<T, Serializable>> attributes = new HashMap<>();
|
||||
|
||||
private final Map<String, Attribute<T, Serializable>> updateAttributeMap = new HashMap<>();
|
||||
|
||||
final String querySQL;
|
||||
@@ -70,8 +70,6 @@ public final class EntityInfo<T> {
|
||||
|
||||
private final Map<String, String> sortOrderbySqls = new ConcurrentHashMap<>();
|
||||
|
||||
private final Map<String, Comparator<T>> sortComparators = new ConcurrentHashMap<>();
|
||||
|
||||
//---------------------计算主键值----------------------------
|
||||
private final int nodeid;
|
||||
|
||||
@@ -225,7 +223,7 @@ public final class EntityInfo<T> {
|
||||
//----------------cache--------------
|
||||
Cacheable c = type.getAnnotation(Cacheable.class);
|
||||
if (this.table == null || (!cacheForbidden && c != null && c.value())) {
|
||||
this.cache = new EntityCache<>(type, creator, primary, attributes);
|
||||
this.cache = new EntityCache<>(this);
|
||||
} else {
|
||||
this.cache = null;
|
||||
}
|
||||
@@ -289,14 +287,6 @@ public final class EntityInfo<T> {
|
||||
this.sortOrderbySqls.put(sort, sql);
|
||||
}
|
||||
|
||||
public Comparator<T> getSortComparator(String sort) {
|
||||
return this.sortComparators.get(sort);
|
||||
}
|
||||
|
||||
protected void putSortComparator(String sort, Comparator<T> comparator) {
|
||||
this.sortComparators.put(sort, comparator);
|
||||
}
|
||||
|
||||
//根据field字段名获取数据库对应的字段名
|
||||
public String getSQLColumn(String fieldname) {
|
||||
return this.aliasmap == null ? fieldname : aliasmap.getOrDefault(fieldname, fieldname);
|
||||
|
||||
@@ -239,10 +239,6 @@ final class FilterBeanNode extends FilterNode {
|
||||
|
||||
@Override
|
||||
protected <T> Predicate<T> createFilterPredicate(final EntityInfo<T> info, FilterBean bean) {
|
||||
return createFilterPredicate(true, info, bean);
|
||||
}
|
||||
|
||||
private <T> Predicate<T> createFilterPredicate(final boolean first, final EntityInfo<T> info, FilterBean bean) {
|
||||
//if ((this.joinSQL == null && first) || this.foreignEntity == null) return super.createFilterPredicate(info, bean);
|
||||
if (this.foreignEntity == null) return super.createFilterPredicate(info, bean);
|
||||
final Map<EntityInfo, Predicate> foreign = new HashMap<>();
|
||||
@@ -252,7 +248,7 @@ final class FilterBeanNode extends FilterNode {
|
||||
for (FilterNode n : this.nodes) {
|
||||
FilterBeanNode node = (FilterBeanNode) n;
|
||||
if (node.foreignEntity == null) {
|
||||
Predicate<T> f = node.createFilterPredicate(false, info, bean);
|
||||
Predicate<T> f = node.createFilterPredicate(info, bean);
|
||||
if (f == null) continue;
|
||||
final Predicate<T> one = result;
|
||||
final Predicate<T> two = f;
|
||||
|
||||
@@ -741,10 +741,10 @@ public class FilterNode {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected static <E> Comparator<E> createFilterComparator(EntityInfo<E> info, Flipper flipper) {
|
||||
protected static <E> Comparator<E> createFilterComparator(EntityCache<E> cache, Flipper flipper) {
|
||||
if (flipper == null || flipper.getSort() == null || flipper.getSort().isEmpty()) return null;
|
||||
final String sort = flipper.getSort();
|
||||
Comparator<E> comparator = info.getSortComparator(sort);
|
||||
Comparator<E> comparator = cache.getSortComparator(sort);
|
||||
if (comparator != null) return comparator;
|
||||
for (String item : sort.split(",")) {
|
||||
if (item.trim().isEmpty()) continue;
|
||||
@@ -752,10 +752,10 @@ public class FilterNode {
|
||||
int pos = sub[0].indexOf('(');
|
||||
Attribute<E, Serializable> attr;
|
||||
if (pos <= 0) {
|
||||
attr = info.getAttribute(sub[0]);
|
||||
attr = cache.info.getAttribute(sub[0]);
|
||||
} else { //含SQL函数
|
||||
int pos2 = sub[0].lastIndexOf(')');
|
||||
final Attribute<E, Serializable> pattr = info.getAttribute(sub[0].substring(pos + 1, pos2));
|
||||
final Attribute<E, Serializable> pattr = cache.info.getAttribute(sub[0].substring(pos + 1, pos2));
|
||||
final String func = sub[0].substring(0, pos);
|
||||
if ("ABS".equalsIgnoreCase(func)) {
|
||||
if (pattr.type() == int.class || pattr.type() == Integer.class) {
|
||||
@@ -895,7 +895,7 @@ public class FilterNode {
|
||||
comparator = comparator.thenComparing(c);
|
||||
}
|
||||
}
|
||||
info.putSortComparator(sort, comparator);
|
||||
cache.putSortComparator(sort, comparator);
|
||||
return comparator;
|
||||
}
|
||||
|
||||
|
||||
24
src/com/wentch/redkale/source/Unique.java
Normal file
24
src/com/wentch/redkale/source/Unique.java
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
import static java.lang.annotation.ElementType.FIELD;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author zhangjx
|
||||
*/
|
||||
@Inherited
|
||||
@Documented
|
||||
@Target({FIELD})
|
||||
@Retention(RUNTIME)
|
||||
@Repeatable(Uniques.class)
|
||||
public @interface Unique {
|
||||
|
||||
String[] columns();
|
||||
}
|
||||
23
src/com/wentch/redkale/source/Uniques.java
Normal file
23
src/com/wentch/redkale/source/Uniques.java
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
import static java.lang.annotation.ElementType.FIELD;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author zhangjx
|
||||
*/
|
||||
@Inherited
|
||||
@Documented
|
||||
@Target({FIELD})
|
||||
@Retention(RUNTIME)
|
||||
public @interface Uniques {
|
||||
|
||||
Unique[] value();
|
||||
}
|
||||
Reference in New Issue
Block a user