Commit 52ab135cb2583d15fd40fa6c81f74c7fd27694f6
1 parent
43ed0860
Fix entity duplication on duplicated attributes
Showing
3 changed files
with
19 additions
and
7 deletions
@@ -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 | } |