完善抄表记录

This commit is contained in:
2024-01-04 20:34:05 +08:00
parent d717480a0e
commit 8931daadbd
9 changed files with 420 additions and 239 deletions

View File

@@ -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;
}
}

View File

@@ -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;
}

View File

@@ -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);
}
}

View File

@@ -51,4 +51,5 @@ public class MeterLogController {
public Page<MeterLogDto> list(@RequestBody CommonQuery request) {
return this.service.list(request);
}
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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());
}
}

View File

@@ -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;
}

View File

@@ -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();
}
}