mirror of
https://codeup.aliyun.com/64f7d6b8ce01efaafef1e678/coal/coal.git
synced 2026-01-25 07:46:40 +08:00
完善抄表记录
This commit is contained in:
@@ -3,12 +3,16 @@ package cn.lihongjie.coal.base.dto;
|
||||
import cn.lihongjie.coal.exception.BizException;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.common.base.CaseFormat;
|
||||
import com.google.common.base.Splitter;
|
||||
|
||||
import io.hypersistence.utils.hibernate.query.ListResultTransformer;
|
||||
import io.vavr.Function4;
|
||||
import io.vavr.Tuple;
|
||||
import io.vavr.Tuple2;
|
||||
|
||||
import jakarta.persistence.EntityManager;
|
||||
import jakarta.persistence.Query;
|
||||
import jakarta.persistence.criteria.*;
|
||||
import jakarta.persistence.metamodel.Attribute;
|
||||
import jakarta.persistence.metamodel.EntityType;
|
||||
@@ -17,16 +21,20 @@ import lombok.*;
|
||||
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.poi.ss.formula.functions.T;
|
||||
import org.hibernate.query.sqm.internal.SqmCriteriaNodeBuilder;
|
||||
import org.springframework.core.convert.ConversionFailedException;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Data
|
||||
@@ -37,6 +45,8 @@ public class CommonQuery {
|
||||
Function4<Root, CriteriaBuilder, QueryItem, ConversionService, Predicate>>
|
||||
map = new HashMap<>();
|
||||
|
||||
public static Map<String, Class> classMap = new HashMap<>();
|
||||
|
||||
static {
|
||||
map.put(
|
||||
Tuple.of("like", String.class),
|
||||
@@ -502,16 +512,20 @@ public class CommonQuery {
|
||||
map.put(
|
||||
Tuple.of("in", String.class),
|
||||
(Root root, CriteriaBuilder criteriaBuilder, QueryItem x, ConversionService c) -> {
|
||||
return ((SqmCriteriaNodeBuilder)criteriaBuilder)
|
||||
.in(parseKey(root, x.key),
|
||||
Arrays.stream(getArray(x)).map(i -> c.convert(i, String.class)).toList());
|
||||
return ((SqmCriteriaNodeBuilder) criteriaBuilder)
|
||||
.in(
|
||||
parseKey(root, x.key),
|
||||
Arrays.stream(getArray(x))
|
||||
.map(i -> c.convert(i, String.class))
|
||||
.toList());
|
||||
});
|
||||
|
||||
map.put(
|
||||
Tuple.of("in", Integer.class),
|
||||
(Root root, CriteriaBuilder criteriaBuilder, QueryItem x, ConversionService c) -> {
|
||||
return ((SqmCriteriaNodeBuilder)criteriaBuilder)
|
||||
.in(parseKey(root, x.key),
|
||||
return ((SqmCriteriaNodeBuilder) criteriaBuilder)
|
||||
.in(
|
||||
parseKey(root, x.key),
|
||||
Arrays.stream(getArray(x))
|
||||
.map(i -> c.convert(i, Integer.class))
|
||||
.toList());
|
||||
@@ -520,8 +534,9 @@ public class CommonQuery {
|
||||
map.put(
|
||||
Tuple.of("in", Long.class),
|
||||
(Root root, CriteriaBuilder criteriaBuilder, QueryItem x, ConversionService c) -> {
|
||||
return ((SqmCriteriaNodeBuilder)criteriaBuilder)
|
||||
.in(parseKey(root, x.key),
|
||||
return ((SqmCriteriaNodeBuilder) criteriaBuilder)
|
||||
.in(
|
||||
parseKey(root, x.key),
|
||||
Arrays.stream(getArray(x))
|
||||
.map(i -> c.convert(i, Long.class))
|
||||
.toList());
|
||||
@@ -530,8 +545,9 @@ public class CommonQuery {
|
||||
map.put(
|
||||
Tuple.of("in", Double.class),
|
||||
(Root root, CriteriaBuilder criteriaBuilder, QueryItem x, ConversionService c) -> {
|
||||
return ((SqmCriteriaNodeBuilder)criteriaBuilder)
|
||||
.in(parseKey(root, x.key),
|
||||
return ((SqmCriteriaNodeBuilder) criteriaBuilder)
|
||||
.in(
|
||||
parseKey(root, x.key),
|
||||
Arrays.stream(getArray(x))
|
||||
.map(i -> c.convert(i, Double.class))
|
||||
.toList());
|
||||
@@ -539,8 +555,9 @@ public class CommonQuery {
|
||||
map.put(
|
||||
Tuple.of("in", BigDecimal.class),
|
||||
(Root root, CriteriaBuilder criteriaBuilder, QueryItem x, ConversionService c) -> {
|
||||
return ((SqmCriteriaNodeBuilder)criteriaBuilder)
|
||||
.in(parseKey(root, x.key),
|
||||
return ((SqmCriteriaNodeBuilder) criteriaBuilder)
|
||||
.in(
|
||||
parseKey(root, x.key),
|
||||
Arrays.stream(getArray(x))
|
||||
.map(i -> c.convert(i, BigDecimal.class))
|
||||
.toList());
|
||||
@@ -549,8 +566,9 @@ public class CommonQuery {
|
||||
map.put(
|
||||
Tuple.of("in", LocalDate.class),
|
||||
(Root root, CriteriaBuilder criteriaBuilder, QueryItem x, ConversionService c) -> {
|
||||
return ((SqmCriteriaNodeBuilder)criteriaBuilder)
|
||||
.in(parseKey(root, x.key),
|
||||
return ((SqmCriteriaNodeBuilder) criteriaBuilder)
|
||||
.in(
|
||||
parseKey(root, x.key),
|
||||
Arrays.stream(getArray(x))
|
||||
.map(i -> c.convert(i, LocalDate.class))
|
||||
.toList());
|
||||
@@ -558,8 +576,9 @@ public class CommonQuery {
|
||||
map.put(
|
||||
Tuple.of("in", LocalDateTime.class),
|
||||
(Root root, CriteriaBuilder criteriaBuilder, QueryItem x, ConversionService c) -> {
|
||||
return ((SqmCriteriaNodeBuilder)criteriaBuilder)
|
||||
.in(parseKey(root, x.key),
|
||||
return ((SqmCriteriaNodeBuilder) criteriaBuilder)
|
||||
.in(
|
||||
parseKey(root, x.key),
|
||||
Arrays.stream(getArray(x))
|
||||
.map(i -> c.convert(i, LocalDateTime.class))
|
||||
.toList());
|
||||
@@ -568,8 +587,9 @@ public class CommonQuery {
|
||||
map.put(
|
||||
Tuple.of("nin", String.class),
|
||||
(Root root, CriteriaBuilder criteriaBuilder, QueryItem x, ConversionService c) -> {
|
||||
return ((SqmCriteriaNodeBuilder)criteriaBuilder)
|
||||
.in(parseKey(root, x.key),
|
||||
return ((SqmCriteriaNodeBuilder) criteriaBuilder)
|
||||
.in(
|
||||
parseKey(root, x.key),
|
||||
Arrays.stream(getArray(x))
|
||||
.map(i -> c.convert(i, String.class))
|
||||
.toList())
|
||||
@@ -579,8 +599,9 @@ public class CommonQuery {
|
||||
map.put(
|
||||
Tuple.of("nin", Integer.class),
|
||||
(Root root, CriteriaBuilder criteriaBuilder, QueryItem x, ConversionService c) -> {
|
||||
return ((SqmCriteriaNodeBuilder)criteriaBuilder)
|
||||
.in(parseKey(root, x.key),
|
||||
return ((SqmCriteriaNodeBuilder) criteriaBuilder)
|
||||
.in(
|
||||
parseKey(root, x.key),
|
||||
Arrays.stream(getArray(x))
|
||||
.map(i -> c.convert(i, Integer.class))
|
||||
.toList())
|
||||
@@ -590,8 +611,9 @@ public class CommonQuery {
|
||||
map.put(
|
||||
Tuple.of("nin", Long.class),
|
||||
(Root root, CriteriaBuilder criteriaBuilder, QueryItem x, ConversionService c) -> {
|
||||
return ((SqmCriteriaNodeBuilder)criteriaBuilder)
|
||||
.in(parseKey(root, x.key),
|
||||
return ((SqmCriteriaNodeBuilder) criteriaBuilder)
|
||||
.in(
|
||||
parseKey(root, x.key),
|
||||
Arrays.stream(getArray(x))
|
||||
.map(i -> c.convert(i, Long.class))
|
||||
.toList())
|
||||
@@ -601,8 +623,9 @@ public class CommonQuery {
|
||||
map.put(
|
||||
Tuple.of("nin", Double.class),
|
||||
(Root root, CriteriaBuilder criteriaBuilder, QueryItem x, ConversionService c) -> {
|
||||
return ((SqmCriteriaNodeBuilder)criteriaBuilder)
|
||||
.in(parseKey(root, x.key),
|
||||
return ((SqmCriteriaNodeBuilder) criteriaBuilder)
|
||||
.in(
|
||||
parseKey(root, x.key),
|
||||
Arrays.stream(getArray(x))
|
||||
.map(i -> c.convert(i, Double.class))
|
||||
.toList())
|
||||
@@ -611,8 +634,9 @@ public class CommonQuery {
|
||||
map.put(
|
||||
Tuple.of("nin", BigDecimal.class),
|
||||
(Root root, CriteriaBuilder criteriaBuilder, QueryItem x, ConversionService c) -> {
|
||||
return ((SqmCriteriaNodeBuilder)criteriaBuilder)
|
||||
.in(parseKey(root, x.key),
|
||||
return ((SqmCriteriaNodeBuilder) criteriaBuilder)
|
||||
.in(
|
||||
parseKey(root, x.key),
|
||||
Arrays.stream(getArray(x))
|
||||
.map(i -> c.convert(i, BigDecimal.class))
|
||||
.toList())
|
||||
@@ -622,8 +646,9 @@ public class CommonQuery {
|
||||
map.put(
|
||||
Tuple.of("nin", LocalDate.class),
|
||||
(Root root, CriteriaBuilder criteriaBuilder, QueryItem x, ConversionService c) -> {
|
||||
return ((SqmCriteriaNodeBuilder)criteriaBuilder)
|
||||
.in(parseKey(root, x.key),
|
||||
return ((SqmCriteriaNodeBuilder) criteriaBuilder)
|
||||
.in(
|
||||
parseKey(root, x.key),
|
||||
Arrays.stream(getArray(x))
|
||||
.map(i -> c.convert(i, LocalDate.class))
|
||||
.toList())
|
||||
@@ -632,8 +657,9 @@ public class CommonQuery {
|
||||
map.put(
|
||||
Tuple.of("nin", LocalDateTime.class),
|
||||
(Root root, CriteriaBuilder criteriaBuilder, QueryItem x, ConversionService c) -> {
|
||||
return ((SqmCriteriaNodeBuilder)criteriaBuilder)
|
||||
.in(parseKey(root, x.key),
|
||||
return ((SqmCriteriaNodeBuilder) criteriaBuilder)
|
||||
.in(
|
||||
parseKey(root, x.key),
|
||||
Arrays.stream(getArray(x))
|
||||
.map(i -> c.convert(i, LocalDateTime.class))
|
||||
.toList())
|
||||
@@ -641,18 +667,6 @@ public class CommonQuery {
|
||||
});
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public static String[] getArray(QueryItem x) {
|
||||
if (!StringUtils.isEmpty(x.value)) {
|
||||
|
||||
if (x.value.startsWith("[")){
|
||||
return new ObjectMapper().readValue(x.value, String[].class);
|
||||
}
|
||||
return x.value.split(",");
|
||||
}
|
||||
return new String[0];
|
||||
}
|
||||
|
||||
private List<QueryItem> items;
|
||||
private Integer pageNo = 0;
|
||||
private Integer pageSize = Integer.MAX_VALUE;
|
||||
@@ -792,6 +806,306 @@ public class CommonQuery {
|
||||
};
|
||||
}
|
||||
|
||||
static {
|
||||
classMap.put("string", String.class);
|
||||
classMap.put("integer", Integer.class);
|
||||
classMap.put("long", Long.class);
|
||||
classMap.put("double", Double.class);
|
||||
classMap.put("bigdecimal", BigDecimal.class);
|
||||
classMap.put("localdate", LocalDate.class);
|
||||
classMap.put("localdatetime", LocalDateTime.class);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public static String[] getArray(QueryItem x) {
|
||||
if (!StringUtils.isEmpty(x.value)) {
|
||||
|
||||
if (x.value.startsWith("[")) {
|
||||
return new ObjectMapper().readValue(x.value, String[].class);
|
||||
}
|
||||
return x.value.split(",");
|
||||
}
|
||||
return new String[0];
|
||||
}
|
||||
|
||||
public <T> Query nativeQuery(
|
||||
EntityManager em,
|
||||
ConversionService conversionService,
|
||||
String s,
|
||||
Class<T> resultClass,
|
||||
Boolean count) {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
RandomNameGenerator randomNameGenerator = new RandomNameGenerator();
|
||||
|
||||
String tableName = randomNameGenerator.generate();
|
||||
|
||||
HashMap<String, Object> paramMap = new HashMap<>();
|
||||
|
||||
if (count) {
|
||||
sb.append("select count(1) from (").append(s).append(") as ").append(tableName);
|
||||
} else {
|
||||
|
||||
sb.append("select * from (").append(s).append(") as ").append(tableName);
|
||||
}
|
||||
|
||||
if (CollectionUtils.isNotEmpty(items)) {
|
||||
sb.append(" where 1=1 and (");
|
||||
|
||||
items.forEach(x -> x.setGroup(StringUtils.defaultIfBlank(x.getGroup(), "default")));
|
||||
|
||||
Map<String, List<QueryItem>> group =
|
||||
items.stream().collect(Collectors.groupingBy(i -> i.group));
|
||||
|
||||
List<String> orPredicates = new ArrayList<>();
|
||||
int index = 0;
|
||||
for (List<QueryItem> queryItems : group.values()) {
|
||||
|
||||
if (index++ != 0) {
|
||||
sb.append(" or ");
|
||||
}
|
||||
|
||||
sb.append("(");
|
||||
int qindex = 0;
|
||||
for (QueryItem queryItem : queryItems) {
|
||||
|
||||
String varName = randomNameGenerator.generate();
|
||||
if (qindex++ != 0) {
|
||||
sb.append(" and ");
|
||||
}
|
||||
sb.append(" (");
|
||||
switch (queryItem.opt) {
|
||||
case "like":
|
||||
sb.append(queryItem.key)
|
||||
.append(" like '%' || ")
|
||||
.append(":")
|
||||
.append(varName)
|
||||
.append(" || '%'");
|
||||
paramMap.put(
|
||||
varName,
|
||||
toNativeQueryParam(queryItem, conversionService, false));
|
||||
break;
|
||||
case "nlike":
|
||||
sb.append(queryItem.key)
|
||||
.append(" not like '%' || ")
|
||||
.append(":")
|
||||
.append(varName)
|
||||
.append(" || '%'");
|
||||
paramMap.put(
|
||||
varName,
|
||||
toNativeQueryParam(queryItem, conversionService, false));
|
||||
break;
|
||||
|
||||
case "null":
|
||||
sb.append(queryItem.key).append(" is null");
|
||||
break;
|
||||
case "nnull":
|
||||
sb.append(queryItem.key).append(" is not null");
|
||||
break;
|
||||
case "eq":
|
||||
sb.append(queryItem.key).append(" = ").append(":").append(varName);
|
||||
paramMap.put(
|
||||
varName,
|
||||
toNativeQueryParam(queryItem, conversionService, false));
|
||||
break;
|
||||
case "neq":
|
||||
sb.append(queryItem.key).append(" != ").append(":").append(varName);
|
||||
paramMap.put(
|
||||
varName,
|
||||
toNativeQueryParam(queryItem, conversionService, false));
|
||||
break;
|
||||
case "between":
|
||||
sb.append(queryItem.key)
|
||||
.append(" between ")
|
||||
.append(":")
|
||||
.append(varName)
|
||||
.append(" and ")
|
||||
.append(":")
|
||||
.append(varName)
|
||||
.append("_2");
|
||||
paramMap.put(
|
||||
varName,
|
||||
toNativeQueryParam(queryItem, conversionService, true));
|
||||
paramMap.put(
|
||||
varName + "_2",
|
||||
toNativeQueryParam(queryItem, conversionService, false));
|
||||
break;
|
||||
case "lt":
|
||||
sb.append(queryItem.key).append(" < ").append(":").append(varName);
|
||||
paramMap.put(
|
||||
varName,
|
||||
toNativeQueryParam(queryItem, conversionService, false));
|
||||
break;
|
||||
case "le":
|
||||
sb.append(queryItem.key).append(" <= ").append(":").append(varName);
|
||||
paramMap.put(
|
||||
varName,
|
||||
toNativeQueryParam(queryItem, conversionService, false));
|
||||
break;
|
||||
case "gt":
|
||||
sb.append(queryItem.key).append(" > ").append(":").append(varName);
|
||||
paramMap.put(
|
||||
varName,
|
||||
toNativeQueryParam(queryItem, conversionService, false));
|
||||
break;
|
||||
case "ge":
|
||||
sb.append(queryItem.key).append(" >= ").append(":").append(varName);
|
||||
paramMap.put(
|
||||
varName,
|
||||
toNativeQueryParam(queryItem, conversionService, false));
|
||||
break;
|
||||
case "empty":
|
||||
sb.append("cardinality(").append(queryItem.key).append(") = 0");
|
||||
break;
|
||||
case "nempty":
|
||||
sb.append("cardinality(").append(queryItem.key).append(") > 0");
|
||||
break;
|
||||
case "in":
|
||||
sb.append(queryItem.key)
|
||||
.append(" = any(")
|
||||
.append(":")
|
||||
.append(varName)
|
||||
.append(")");
|
||||
paramMap.put(
|
||||
varName,
|
||||
toNativeQueryParam(queryItem, conversionService, false));
|
||||
break;
|
||||
case "nin":
|
||||
sb.append(queryItem.key)
|
||||
.append(" != all(")
|
||||
.append(":")
|
||||
.append(varName)
|
||||
.append(")");
|
||||
paramMap.put(
|
||||
varName,
|
||||
toNativeQueryParam(queryItem, conversionService, false));
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException("无法识别的查询 " + queryItem);
|
||||
}
|
||||
|
||||
sb.append(")");
|
||||
}
|
||||
|
||||
sb.append(")");
|
||||
}
|
||||
sb.append(")");
|
||||
}
|
||||
|
||||
sb.append(" ");
|
||||
Query query;
|
||||
|
||||
if (!count) {
|
||||
|
||||
if (CollectionUtils.isNotEmpty(orders)) {
|
||||
sb.append(" order by ");
|
||||
int index = 0;
|
||||
for (Order order : orders) {
|
||||
if (index++ != 0) {
|
||||
sb.append(",");
|
||||
}
|
||||
sb.append(order.property).append(" ").append(order.direction.name());
|
||||
}
|
||||
}
|
||||
|
||||
sb.append(" limit ").append(pageSize).append(" offset ").append(pageNo * pageSize);
|
||||
|
||||
query = em.createNativeQuery(sb.toString());
|
||||
|
||||
paramMap.forEach((k, v) -> query.setParameter(k, v));
|
||||
query.unwrap(org.hibernate.query.NativeQuery.class)
|
||||
.setResultTransformer(
|
||||
new ListResultTransformer() {
|
||||
@SneakyThrows
|
||||
@Override
|
||||
public Object transformTuple(Object[] tuple, String[] aliases) {
|
||||
|
||||
T object = resultClass.newInstance();
|
||||
|
||||
for (int i = 0; i < aliases.length; i++) {
|
||||
String alias = aliases[i];
|
||||
Object value = tuple[i];
|
||||
|
||||
Field field =
|
||||
ReflectionUtils.findField(
|
||||
resultClass,
|
||||
CaseFormat.LOWER_UNDERSCORE.to(
|
||||
CaseFormat.LOWER_CAMEL, alias));
|
||||
|
||||
if (field != null) {
|
||||
|
||||
ReflectionUtils.makeAccessible(field);
|
||||
ReflectionUtils.setField(
|
||||
field,
|
||||
object,
|
||||
conversionService.convert(
|
||||
value, field.getType()));
|
||||
}
|
||||
}
|
||||
|
||||
return object;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
|
||||
query = em.createNativeQuery(sb.toString());
|
||||
|
||||
paramMap.forEach((k, v) -> query.setParameter(k, v));
|
||||
}
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
private Object toNativeQueryParam(
|
||||
QueryItem queryItem, ConversionService conversionService, boolean b) {
|
||||
Class targetType = classMap.get(queryItem.type);
|
||||
|
||||
switch (queryItem.opt) {
|
||||
case "in":
|
||||
case "nin":
|
||||
return Arrays.stream(getArray(queryItem))
|
||||
.map(
|
||||
i -> {
|
||||
return conversionService.convert(i, targetType);
|
||||
})
|
||||
.toList();
|
||||
case "between":
|
||||
return b
|
||||
? conversionService.convert(queryItem.min, targetType)
|
||||
: conversionService.convert(queryItem.max, targetType);
|
||||
}
|
||||
return conversionService.convert(queryItem.value, targetType);
|
||||
}
|
||||
|
||||
public static class RandomNameGenerator {
|
||||
|
||||
private final Set<String> names = new HashSet<>();
|
||||
|
||||
public String generate() {
|
||||
|
||||
int count = 0;
|
||||
|
||||
while (true) {
|
||||
|
||||
count++;
|
||||
|
||||
if (count > 100) {
|
||||
throw new RuntimeException("无法生成随机名称");
|
||||
}
|
||||
|
||||
String name = "t_" + ThreadLocalRandom.current().nextInt(1, 100000);
|
||||
|
||||
if (names.contains(name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
names.add(name);
|
||||
return name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class Order {
|
||||
|
||||
@@ -809,5 +1123,6 @@ public class CommonQuery {
|
||||
@Builder.Default private String group = "default";
|
||||
private String min;
|
||||
private String max;
|
||||
private String type;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,9 +8,34 @@ import jakarta.persistence.ManyToOne;
|
||||
import lombok.Data;
|
||||
|
||||
import org.hibernate.annotations.Comment;
|
||||
import org.hibernate.annotations.Formula;
|
||||
import org.hibernate.annotations.Subselect;
|
||||
|
||||
@Data
|
||||
@Entity
|
||||
@Subselect("""
|
||||
|
||||
|
||||
select distinct on (DATE_TRUNC('day', time), meter_id, organization_id) id,
|
||||
create_time,
|
||||
create_user_id,
|
||||
file_ids,
|
||||
update_time,
|
||||
update_user_id,
|
||||
code,
|
||||
name,
|
||||
remarks,
|
||||
sort_key,
|
||||
status,
|
||||
organization_id,
|
||||
DATE_TRUNC('day', time) as time,
|
||||
value,
|
||||
meter_id
|
||||
from t_meter_log
|
||||
|
||||
order by DATE_TRUNC('day', time), meter_id, organization_id, t_meter_log.time desc
|
||||
|
||||
""")
|
||||
public class MeterDayLogEntity extends OrgCommonEntity {
|
||||
|
||||
@ManyToOne
|
||||
@@ -22,9 +47,8 @@ public class MeterDayLogEntity extends OrgCommonEntity {
|
||||
@Comment("抄表值")
|
||||
private java.lang.Double value;
|
||||
|
||||
@Comment("上次抄表值")
|
||||
@Formula("( lag(value, 1, (select tm.init_value from t_meter tm where tm.id = meter_id)) over (partition by meter_id order by time asc ) )")
|
||||
private java.lang.Double previousValue;
|
||||
|
||||
@Comment("使用量")
|
||||
@Formula(" ( value - ( lag(value, 1, (select tm.init_value from t_meter tm where tm.id = meter_id)) over (partition by meter_id order by time asc ) ) )")
|
||||
private java.lang.Double usage;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package cn.lihongjie.coal.meterDayLog.service;
|
||||
import cn.lihongjie.coal.base.dto.CommonQuery;
|
||||
import cn.lihongjie.coal.base.dto.IdRequest;
|
||||
import cn.lihongjie.coal.base.service.BaseService;
|
||||
import cn.lihongjie.coal.meter.entity.MeterEntity;
|
||||
import cn.lihongjie.coal.meterDayLog.dto.CreateMeterDayLogDto;
|
||||
import cn.lihongjie.coal.meterDayLog.dto.MeterDayLogDto;
|
||||
import cn.lihongjie.coal.meterDayLog.dto.UpdateMeterDayLogDto;
|
||||
@@ -14,7 +13,6 @@ import cn.lihongjie.coal.meterMonthLog.service.MeterMonthLogService;
|
||||
|
||||
import jakarta.persistence.EntityManager;
|
||||
import jakarta.persistence.PersistenceContext;
|
||||
import jakarta.persistence.Query;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@@ -26,9 +24,6 @@ import org.springframework.data.domain.Sort;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
@Transactional
|
||||
@@ -84,64 +79,4 @@ class MeterDayLogService extends BaseService<MeterDayLogEntity, MeterDayLogRepos
|
||||
;
|
||||
}
|
||||
|
||||
public void syncMeter(String meterId, LocalDateTime time) {
|
||||
|
||||
MeterEntity meter = new MeterEntity();
|
||||
meter.setId(meterId);
|
||||
repository.deleteByMeter(meter);
|
||||
|
||||
Query nativeQuery =
|
||||
entityManager.createNativeQuery(
|
||||
"""
|
||||
|
||||
select cast(DATE_TRUNC('day', time) as date) as time,
|
||||
meter_id,
|
||||
sum(usage) as value
|
||||
from t_meter_log
|
||||
where meter_id = :meterId group by cast(DATE_TRUNC('day', time) as date), meter_id
|
||||
""");
|
||||
|
||||
nativeQuery.setParameter("meterId", meterId);
|
||||
|
||||
nativeQuery
|
||||
.getResultList()
|
||||
.forEach(
|
||||
o -> {
|
||||
Object[] result = (Object[]) o;
|
||||
MeterDayLogEntity entity = new MeterDayLogEntity();
|
||||
entity.setMeter(meter);
|
||||
entity.setTime(conversionService.convert(result[0], LocalDate.class));
|
||||
entity.setValue((Double) result[2]);
|
||||
repository.save(entity);
|
||||
});
|
||||
|
||||
Query nativeQuery2 =
|
||||
entityManager.createNativeQuery(
|
||||
"""
|
||||
|
||||
|
||||
update t_meter_day_log ta
|
||||
|
||||
|
||||
set previous_value = tb.previous_value,
|
||||
usage = ta.value - tb.previous_value
|
||||
|
||||
from (
|
||||
|
||||
select id, time, value, COALESCE(lag(value) over (order by time), value ) as previous_value from t_meter_day_log where meter_id = :meterId
|
||||
) tb
|
||||
|
||||
where tb.id = ta.id
|
||||
|
||||
|
||||
""");
|
||||
|
||||
nativeQuery2.setParameter("meterId", meterId);
|
||||
|
||||
nativeQuery2.executeUpdate();
|
||||
|
||||
|
||||
meterMonthLogService.syncMeter(meterId, time);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,4 +51,5 @@ public class MeterLogController {
|
||||
public Page<MeterLogDto> list(@RequestBody CommonQuery request) {
|
||||
return this.service.list(request);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -11,6 +11,8 @@ import org.hibernate.annotations.Comment;
|
||||
public class MeterLogDto extends OrgCommonDto {
|
||||
private MeterDto meter;
|
||||
|
||||
private String meterId;
|
||||
|
||||
@Comment("抄表时间")
|
||||
private java.time.LocalDateTime time;
|
||||
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
package cn.lihongjie.coal.meterLog.entity;
|
||||
|
||||
import cn.lihongjie.coal.annotation.HyperTable;
|
||||
import cn.lihongjie.coal.base.entity.OrgCommonEntity;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Index;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@@ -15,9 +12,6 @@ import org.hibernate.annotations.Formula;
|
||||
|
||||
@Data
|
||||
@Entity
|
||||
@HyperTable
|
||||
@Table(indexes = {@Index(columnList = "id")})
|
||||
|
||||
public class MeterLogEntity extends OrgCommonEntity {
|
||||
|
||||
@ManyToOne private cn.lihongjie.coal.meter.entity.MeterEntity meter;
|
||||
|
||||
@@ -14,7 +14,6 @@ import cn.lihongjie.coal.meterMonthLog.service.MeterMonthLogService;
|
||||
|
||||
import jakarta.persistence.EntityManager;
|
||||
import jakarta.persistence.PersistenceContext;
|
||||
import jakarta.persistence.Query;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@@ -25,19 +24,11 @@ import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.StopWatch;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
@Transactional
|
||||
public
|
||||
class MeterLogService extends BaseService<MeterLogEntity, MeterLogRepository> {
|
||||
public class MeterLogService extends BaseService<MeterLogEntity, MeterLogRepository> {
|
||||
@Autowired private MeterLogRepository repository;
|
||||
|
||||
@Autowired private MeterLogMapper mapper;
|
||||
@@ -49,7 +40,7 @@ class MeterLogService extends BaseService<MeterLogEntity, MeterLogRepository> {
|
||||
MeterLogEntity entity = mapper.toEntity(request);
|
||||
|
||||
this.repository.save(entity);
|
||||
syncMeterLog(entity.getMeter().getId(), request.getTime());
|
||||
|
||||
return getById(entity.getId());
|
||||
}
|
||||
|
||||
@@ -58,22 +49,15 @@ class MeterLogService extends BaseService<MeterLogEntity, MeterLogRepository> {
|
||||
this.mapper.updateEntity(entity, request);
|
||||
|
||||
this.repository.save(entity);
|
||||
syncMeterLog(entity.getMeter().getId(), request.getTime());
|
||||
|
||||
return getById(entity.getId());
|
||||
}
|
||||
|
||||
public void delete(IdRequest request) {
|
||||
List<MeterLogEntity> all = this.repository.findAllById(request.getIds());
|
||||
|
||||
Map<String, List<MeterLogEntity>> groupByMeterId = all.stream().collect(Collectors.groupingBy(l -> l.getMeter().getId()));
|
||||
|
||||
this.repository.deleteAllById(request.getIds());
|
||||
|
||||
|
||||
groupByMeterId.forEach((meterId, meterLogs) -> {
|
||||
syncMeterLog(meterId, meterLogs.stream().sorted(Comparator.comparing(MeterLogEntity::getTime)).findFirst().map(MeterLogEntity::getTime).orElse(LocalDateTime.now()));
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
public MeterLogDto getById(String id) {
|
||||
@@ -94,48 +78,10 @@ class MeterLogService extends BaseService<MeterLogEntity, MeterLogRepository> {
|
||||
return page.map(this.mapper::toDto);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Autowired MeterMonthLogService meterMonthLogService;
|
||||
|
||||
@Autowired MeterDayLogService meterDayLogService;
|
||||
|
||||
public void syncMeterLog(String meterId, LocalDateTime time) {
|
||||
log.info("syncMeterLog {} {} 开始同步", meterId, time);
|
||||
|
||||
Query nativeQuery =
|
||||
entityManager.createNativeQuery(
|
||||
"""
|
||||
|
||||
|
||||
update t_meter_log ta
|
||||
|
||||
|
||||
set previous_value = tb.previous_value,
|
||||
usage = ta.value - tb.previous_value
|
||||
|
||||
from (
|
||||
|
||||
select id, time, value, COALESCE(lag(value) over (order by time), value ) as previous_value from t_meter_log where meter_id = :meterId
|
||||
) tb
|
||||
|
||||
where tb.id = ta.id
|
||||
|
||||
|
||||
""");
|
||||
|
||||
nativeQuery.setParameter("meterId", meterId);
|
||||
// nativeQuery.setParameter("time", time);
|
||||
|
||||
StopWatch stopWatch = new StopWatch();
|
||||
stopWatch.start("syncMeterLog");
|
||||
int count = nativeQuery.executeUpdate();
|
||||
|
||||
stopWatch.stop();
|
||||
|
||||
stopWatch.start("syncMeterDayLog");
|
||||
|
||||
meterDayLogService.syncMeter(meterId, time);
|
||||
stopWatch.stop();
|
||||
|
||||
log.info("syncMeterLog {} 更新了 {} 条数据\n {}", meterId, count, stopWatch.prettyPrint());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,9 +8,34 @@ import jakarta.persistence.ManyToOne;
|
||||
import lombok.Data;
|
||||
|
||||
import org.hibernate.annotations.Comment;
|
||||
import org.hibernate.annotations.Formula;
|
||||
import org.hibernate.annotations.Subselect;
|
||||
|
||||
@Data
|
||||
@Entity
|
||||
@Subselect("""
|
||||
|
||||
|
||||
select distinct on (DATE_TRUNC('month', time), meter_id, organization_id) id,
|
||||
create_time,
|
||||
create_user_id,
|
||||
file_ids,
|
||||
update_time,
|
||||
update_user_id,
|
||||
code,
|
||||
name,
|
||||
remarks,
|
||||
sort_key,
|
||||
status,
|
||||
organization_id,
|
||||
DATE_TRUNC('month', time) as time,
|
||||
value,
|
||||
meter_id
|
||||
from t_meter_log
|
||||
|
||||
order by DATE_TRUNC('month', time), meter_id, organization_id, t_meter_log.time desc
|
||||
|
||||
""")
|
||||
public class MeterMonthLogEntity extends OrgCommonEntity {
|
||||
|
||||
@ManyToOne private cn.lihongjie.coal.meter.entity.MeterEntity meter;
|
||||
@@ -21,9 +46,9 @@ public class MeterMonthLogEntity extends OrgCommonEntity {
|
||||
@Comment("抄表值")
|
||||
private java.lang.Double value;
|
||||
|
||||
@Comment("上次抄表值")
|
||||
private java.lang.Double previousValue;
|
||||
|
||||
@Comment("使用量")
|
||||
@Formula("( lag(value, 1, (select tm.init_value from t_meter tm where tm.id = meter_id)) over (partition by meter_id order by time asc ) )")
|
||||
private java.lang.Double previousValue;
|
||||
@Formula(" ( value - ( lag(value, 1, (select tm.init_value from t_meter tm where tm.id = meter_id)) over (partition by meter_id order by time asc ) ) )")
|
||||
private java.lang.Double usage;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package cn.lihongjie.coal.meterMonthLog.service;
|
||||
import cn.lihongjie.coal.base.dto.CommonQuery;
|
||||
import cn.lihongjie.coal.base.dto.IdRequest;
|
||||
import cn.lihongjie.coal.base.service.BaseService;
|
||||
import cn.lihongjie.coal.meter.entity.MeterEntity;
|
||||
import cn.lihongjie.coal.meterMonthLog.dto.CreateMeterMonthLogDto;
|
||||
import cn.lihongjie.coal.meterMonthLog.dto.MeterMonthLogDto;
|
||||
import cn.lihongjie.coal.meterMonthLog.dto.UpdateMeterMonthLogDto;
|
||||
@@ -13,7 +12,6 @@ import cn.lihongjie.coal.meterMonthLog.repository.MeterMonthLogRepository;
|
||||
|
||||
import jakarta.persistence.EntityManager;
|
||||
import jakarta.persistence.PersistenceContext;
|
||||
import jakarta.persistence.Query;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@@ -25,9 +23,6 @@ import org.springframework.data.domain.Sort;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
@Transactional
|
||||
@@ -79,60 +74,4 @@ class MeterMonthLogService extends BaseService<MeterMonthLogEntity, MeterMonthLo
|
||||
}
|
||||
|
||||
|
||||
public void syncMeter(String meterId, LocalDateTime time) {
|
||||
|
||||
MeterEntity meter = new MeterEntity();
|
||||
meter.setId(meterId);
|
||||
repository.deleteByMeter(meter);
|
||||
|
||||
Query nativeQuery =
|
||||
entityManager.createNativeQuery(
|
||||
"""
|
||||
|
||||
select cast(DATE_TRUNC('month', time) as date) as time,
|
||||
meter_id,
|
||||
sum(usage) as value
|
||||
from t_meter_log
|
||||
where meter_id = :meterId group by cast(DATE_TRUNC('month', time) as date), meter_id
|
||||
""");
|
||||
|
||||
nativeQuery.setParameter("meterId", meterId);
|
||||
|
||||
nativeQuery
|
||||
.getResultList()
|
||||
.forEach(
|
||||
o -> {
|
||||
Object[] result = (Object[]) o;
|
||||
MeterMonthLogEntity entity = new MeterMonthLogEntity();
|
||||
entity.setMeter(meter);
|
||||
entity.setTime(conversionService.convert(result[0], LocalDate.class));
|
||||
entity.setValue((Double) result[2]);
|
||||
repository.save(entity);
|
||||
});
|
||||
|
||||
Query nativeQuery2 =
|
||||
entityManager.createNativeQuery(
|
||||
"""
|
||||
|
||||
|
||||
update t_meter_month_log ta
|
||||
|
||||
|
||||
set previous_value = tb.previous_value,
|
||||
usage = ta.value - tb.previous_value
|
||||
|
||||
from (
|
||||
|
||||
select id, time, value, COALESCE(lag(value) over (order by time), value ) as previous_value from t_meter_month_log where meter_id = :meterId
|
||||
) tb
|
||||
|
||||
where tb.id = ta.id
|
||||
|
||||
|
||||
""");
|
||||
|
||||
nativeQuery2.setParameter("meterId", meterId);
|
||||
|
||||
nativeQuery2.executeUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user