Commit 52ab135cb2583d15fd40fa6c81f74c7fd27694f6

Authored by Andrii Shvaika
1 parent 43ed0860

Fix entity duplication on duplicated attributes

@@ -201,7 +201,7 @@ public abstract class TbAbstractDataSubCtx<T extends AbstractDataQuery<? extends @@ -201,7 +201,7 @@ public abstract class TbAbstractDataSubCtx<T extends AbstractDataQuery<? extends
201 return result; 201 return result;
202 } 202 }
203 203
204 - protected synchronized void update(){ 204 + protected synchronized void update() {
205 long start = System.currentTimeMillis(); 205 long start = System.currentTimeMillis();
206 PageData<EntityData> newData = findEntityData(); 206 PageData<EntityData> newData = findEntityData();
207 long end = System.currentTimeMillis(); 207 long end = System.currentTimeMillis();
@@ -209,11 +209,11 @@ public abstract class TbAbstractDataSubCtx<T extends AbstractDataQuery<? extends @@ -209,11 +209,11 @@ public abstract class TbAbstractDataSubCtx<T extends AbstractDataQuery<? extends
209 stats.getRegularQueryTimeSpent().addAndGet(end - start); 209 stats.getRegularQueryTimeSpent().addAndGet(end - start);
210 Map<EntityId, EntityData> oldDataMap; 210 Map<EntityId, EntityData> oldDataMap;
211 if (data != null && !data.getData().isEmpty()) { 211 if (data != null && !data.getData().isEmpty()) {
212 - oldDataMap = data.getData().stream().collect(Collectors.toMap(EntityData::getEntityId, Function.identity())); 212 + oldDataMap = data.getData().stream().collect(Collectors.toMap(EntityData::getEntityId, Function.identity(), (a, b) -> a));
213 } else { 213 } else {
214 oldDataMap = Collections.emptyMap(); 214 oldDataMap = Collections.emptyMap();
215 } 215 }
216 - Map<EntityId, EntityData> newDataMap = newData.getData().stream().collect(Collectors.toMap(EntityData::getEntityId, Function.identity())); 216 + Map<EntityId, EntityData> newDataMap = newData.getData().stream().collect(Collectors.toMap(EntityData::getEntityId, Function.identity(), (a,b)-> a));
217 if (oldDataMap.size() == newDataMap.size() && oldDataMap.keySet().equals(newDataMap.keySet())) { 217 if (oldDataMap.size() == newDataMap.size() && oldDataMap.keySet().equals(newDataMap.keySet())) {
218 log.trace("[{}][{}] No updates to entity data found", sessionRef.getSessionId(), cmdId); 218 log.trace("[{}][{}] No updates to entity data found", sessionRef.getSessionId(), cmdId);
219 } else { 219 } else {
@@ -337,7 +337,7 @@ public abstract class TbAbstractDataSubCtx<T extends AbstractDataQuery<? extends @@ -337,7 +337,7 @@ public abstract class TbAbstractDataSubCtx<T extends AbstractDataQuery<? extends
337 } 337 }
338 } 338 }
339 339
340 - public void clearDynamicValueSubscriptions(){ 340 + public void clearDynamicValueSubscriptions() {
341 if (subToDynamicValueKeySet != null) { 341 if (subToDynamicValueKeySet != null) {
342 for (Integer subId : subToDynamicValueKeySet) { 342 for (Integer subId : subToDynamicValueKeySet) {
343 localSubscriptionService.cancelSubscription(sessionRef.getSessionId(), subId); 343 localSubscriptionService.cancelSubscription(sessionRef.getSessionId(), subId);
@@ -49,6 +49,7 @@ import org.thingsboard.server.common.data.relation.EntitySearchDirection; @@ -49,6 +49,7 @@ import org.thingsboard.server.common.data.relation.EntitySearchDirection;
49 import org.thingsboard.server.common.data.relation.EntityTypeFilter; 49 import org.thingsboard.server.common.data.relation.EntityTypeFilter;
50 import org.thingsboard.server.dao.util.SqlDao; 50 import org.thingsboard.server.dao.util.SqlDao;
51 51
  52 +import java.util.Arrays;
52 import java.util.Collections; 53 import java.util.Collections;
53 import java.util.HashMap; 54 import java.util.HashMap;
54 import java.util.List; 55 import java.util.List;
@@ -230,6 +231,8 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { @@ -230,6 +231,8 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository {
230 ctx.append(addEntityTableQuery(ctx, query.getEntityFilter(), entityType)); 231 ctx.append(addEntityTableQuery(ctx, query.getEntityFilter(), entityType));
231 ctx.append(" e where "); 232 ctx.append(" e where ");
232 ctx.append(buildEntityWhere(ctx, tenantId, customerId, query.getEntityFilter(), Collections.emptyList(), entityType)); 233 ctx.append(buildEntityWhere(ctx, tenantId, customerId, query.getEntityFilter(), Collections.emptyList(), entityType));
  234 +// log.error("QUERY: {}", ctx.getQuery());
  235 +// Arrays.asList(ctx.getParameterNames()).forEach(param -> log.error("QUERY PARAM: {}->{}", param, ctx.getValue(param)));
233 return transactionTemplate.execute(status -> jdbcTemplate.queryForObject(ctx.getQuery(), ctx, Long.class)); 236 return transactionTemplate.execute(status -> jdbcTemplate.queryForObject(ctx.getQuery(), ctx, Long.class));
234 } 237 }
235 238
@@ -312,6 +315,8 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { @@ -312,6 +315,8 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository {
312 if (pageLink.getPageSize() > 0) { 315 if (pageLink.getPageSize() > 0) {
313 dataQuery = String.format("%s limit %s offset %s", dataQuery, pageLink.getPageSize(), startIndex); 316 dataQuery = String.format("%s limit %s offset %s", dataQuery, pageLink.getPageSize(), startIndex);
314 } 317 }
  318 +// log.error("QUERY: {}", dataQuery);
  319 +// Arrays.asList(ctx.getParameterNames()).forEach(param -> log.error("QUERY PARAM: {}->{}", param, ctx.getValue(param)));
315 List<Map<String, Object>> rows = jdbcTemplate.queryForList(dataQuery, ctx); 320 List<Map<String, Object>> rows = jdbcTemplate.queryForList(dataQuery, ctx);
316 return EntityDataAdapter.createEntityData(pageLink, selectionMapping, rows, totalElements); 321 return EntityDataAdapter.createEntityData(pageLink, selectionMapping, rows, totalElements);
317 }); 322 });
@@ -231,15 +231,17 @@ public class EntityKeyMapping { @@ -231,15 +231,17 @@ public class EntityKeyMapping {
231 } else { 231 } else {
232 entityTypeStr = "'" + entityType.name() + "'"; 232 entityTypeStr = "'" + entityType.name() + "'";
233 } 233 }
234 - String join = hasFilter() ? "left join" : "left outer join";  
235 ctx.addStringParameter(alias + "_key_id", entityKey.getKey()); 234 ctx.addStringParameter(alias + "_key_id", entityKey.getKey());
236 if (entityKey.getType().equals(EntityKeyType.TIME_SERIES)) { 235 if (entityKey.getType().equals(EntityKeyType.TIME_SERIES)) {
  236 + String join = hasFilter() ? "left join" : "left outer join";
237 return String.format("%s ts_kv_latest %s ON %s.entity_id=entities.id AND %s.key = (select key_id from ts_kv_dictionary where key = :%s_key_id)", 237 return String.format("%s ts_kv_latest %s ON %s.entity_id=entities.id AND %s.key = (select key_id from ts_kv_dictionary where key = :%s_key_id)",
238 join, alias, alias, alias, alias); 238 join, alias, alias, alias, alias);
239 } else { 239 } else {
240 - String query = String.format("%s attribute_kv %s ON %s.entity_id=entities.id AND %s.entity_type=%s AND %s.attribute_key=:%s_key_id",  
241 - join, alias, alias, alias, entityTypeStr, alias, alias); 240 + String query;
242 if (!entityKey.getType().equals(EntityKeyType.ATTRIBUTE)) { 241 if (!entityKey.getType().equals(EntityKeyType.ATTRIBUTE)) {
  242 + String join = hasFilter() ? "left join" : "left outer join";
  243 + query = String.format("%s attribute_kv %s ON %s.entity_id=entities.id AND %s.entity_type=%s AND %s.attribute_key=:%s_key_id",
  244 + join, alias, alias, alias, entityTypeStr, alias, alias);
243 String scope; 245 String scope;
244 if (entityKey.getType().equals(EntityKeyType.CLIENT_ATTRIBUTE)) { 246 if (entityKey.getType().equals(EntityKeyType.CLIENT_ATTRIBUTE)) {
245 scope = DataConstants.CLIENT_SCOPE; 247 scope = DataConstants.CLIENT_SCOPE;
@@ -249,6 +251,11 @@ public class EntityKeyMapping { @@ -249,6 +251,11 @@ public class EntityKeyMapping {
249 scope = DataConstants.SERVER_SCOPE; 251 scope = DataConstants.SERVER_SCOPE;
250 } 252 }
251 query = String.format("%s AND %s.attribute_type='%s'", query, alias, scope); 253 query = String.format("%s AND %s.attribute_type='%s'", query, alias, scope);
  254 + } else {
  255 + String join = hasFilter() ? "join LATERAL" : "left join LATERAL";
  256 + query = String.format("%s (select * from attribute_kv %s WHERE %s.entity_id=entities.id AND %s.entity_type=%s AND %s.attribute_key=:%s_key_id " +
  257 + "ORDER BY %s.last_update_ts DESC limit 1) as %s ON true",
  258 + join, alias, alias, alias, entityTypeStr, alias, alias, alias, alias);
252 } 259 }
253 return query; 260 return query;
254 } 261 }