Skip to content

Commit 4d9579e

Browse files
authored
Refactor entity association and caching logic (#1281)
2 parents 2ec4c72 + 1e16558 commit 4d9579e

File tree

21 files changed

+313
-143
lines changed

21 files changed

+313
-143
lines changed
Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,15 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16-
package org.seasar.doma.jdbc.criteria.command;
16+
package org.seasar.doma.jdbc;
1717

1818
import java.util.List;
19+
import java.util.Objects;
1920
import org.seasar.doma.jdbc.entity.EntityType;
2021

21-
public record CacheKey(EntityType<?> entityType, List<?> items) {
22-
static CacheKey of(EntityKey key) {
23-
return new CacheKey(key.getEntityMetamodel().asType(), key.getItems());
22+
public record EntityId(EntityType<?> entityType, List<?> items) {
23+
public EntityId {
24+
Objects.requireNonNull(entityType);
25+
Objects.requireNonNull(items);
2426
}
2527
}

doma-core/src/main/java/org/seasar/doma/jdbc/aggregate/AggregateCommand.java

Lines changed: 27 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import java.util.stream.Stream;
2626
import org.seasar.doma.internal.util.Combinations;
2727
import org.seasar.doma.internal.util.Pair;
28+
import org.seasar.doma.jdbc.EntityId;
2829
import org.seasar.doma.jdbc.command.Command;
2930
import org.seasar.doma.jdbc.command.SelectCommand;
3031
import org.seasar.doma.jdbc.entity.EntityType;
@@ -40,52 +41,48 @@
4041
*/
4142
public class AggregateCommand<RESULT, ENTITY> implements Command<RESULT> {
4243
private final SelectQuery query;
43-
private final EntityType<ENTITY> entityType;
44+
private final EntityType<ENTITY> rootEntityType;
4445
private final StreamReducer<RESULT, ENTITY> streamReducer;
4546
private final AggregateStrategyType aggregateStrategyType;
4647

4748
public AggregateCommand(
4849
SelectQuery query,
49-
EntityType<ENTITY> entityType,
50+
EntityType<ENTITY> rootEntityType,
5051
StreamReducer<RESULT, ENTITY> streamReducer,
5152
AggregateStrategyType aggregateStrategyType) {
5253
this.query = Objects.requireNonNull(query);
53-
this.entityType = Objects.requireNonNull(entityType);
54+
this.rootEntityType = Objects.requireNonNull(rootEntityType);
5455
this.streamReducer = Objects.requireNonNull(streamReducer);
5556
this.aggregateStrategyType = Objects.requireNonNull(aggregateStrategyType);
5657
}
5758

5859
@Override
5960
public RESULT execute() {
60-
Set<AggregateEntityCacheKey> rootEntityKeys = new LinkedHashSet<>();
61-
Map<AggregateEntityCacheKey, Object> entityCache = new HashMap<>();
62-
SelectCommand<List<AggregateEntityPool>> command =
61+
Set<EntityId> rootEntityIds = new LinkedHashSet<>();
62+
Map<EntityId, Object> entityCache = new HashMap<>();
63+
Combinations<AssociationEntityKey> combinations = new Combinations<>();
64+
65+
SelectCommand<List<AssociationEntityPool>> command =
6366
new SelectCommand<>(
6467
query,
65-
new AggregateEntityPoolIterationHandler(
66-
entityType,
68+
new AssociationEntityPoolIterationHandler(
69+
rootEntityType,
6770
aggregateStrategyType,
6871
query.isResultMappingEnsured(),
69-
rootEntityKeys,
72+
rootEntityIds,
7073
entityCache));
71-
List<AggregateEntityPool> entityPools = command.execute();
72-
73-
Combinations<AggregateEntityKey> combinations = new Combinations<>();
74-
for (AggregateEntityPool entityPool : entityPools) {
75-
Map<AggregatePathKey, AggregateEntityPoolEntry> associationCandidate = new HashMap<>();
76-
for (AggregateEntityPoolEntry entry : entityPool) {
77-
associationCandidate.put(entry.entityKey().pathKey(), entry);
78-
}
79-
associate(entityCache, combinations, associationCandidate);
74+
List<AssociationEntityPool> entityPools = command.execute();
75+
for (AssociationEntityPool entityPool : entityPools) {
76+
associate(entityCache, combinations, entityPool);
8077
}
8178

8279
@SuppressWarnings("unchecked")
8380
Stream<ENTITY> stream =
8481
(Stream<ENTITY>)
85-
rootEntityKeys.stream()
82+
rootEntityIds.stream()
8683
.map(entityCache::get)
8784
.filter(Objects::nonNull)
88-
.filter(entityType.getEntityClass()::isInstance);
85+
.filter(rootEntityType.getEntityClass()::isInstance);
8986

9087
return streamReducer.reduce(stream);
9188
}
@@ -95,19 +92,19 @@ public RESULT execute() {
9592
* of linkage rules and updates the cache with newly associated entities.
9693
*/
9794
private void associate(
98-
Map<AggregateEntityCacheKey, Object> entityCache,
99-
Combinations<AggregateEntityKey> combinations,
100-
Map<AggregatePathKey, AggregateEntityPoolEntry> associationCandidate) {
95+
Map<EntityId, Object> entityCache,
96+
Combinations<AssociationEntityKey> combinations,
97+
AssociationEntityPool entityPool) {
10198

10299
for (AssociationLinkerType<?, ?> linkerType :
103100
aggregateStrategyType.getAssociationLinkerTypes()) {
104-
AggregateEntityPoolEntry source = associationCandidate.get(linkerType.getSourcePathKey());
105-
AggregateEntityPoolEntry target = associationCandidate.get(linkerType.getTargetPathKey());
101+
AssociationEntityPoolEntry source = entityPool.get(linkerType.getSourcePathKey());
102+
AssociationEntityPoolEntry target = entityPool.get(linkerType.getTargetPathKey());
106103
if (source == null || target == null) {
107104
continue;
108105
}
109106

110-
Pair<AggregateEntityKey, AggregateEntityKey> keyPair =
107+
Pair<AssociationEntityKey, AssociationEntityKey> keyPair =
111108
new Pair<>(source.entityKey(), target.entityKey());
112109
if (combinations.contains(keyPair)) {
113110
continue;
@@ -117,12 +114,10 @@ private void associate(
117114
@SuppressWarnings("unchecked")
118115
BiFunction<Object, Object, Object> linker =
119116
(BiFunction<Object, Object, Object>) linkerType.getLinker();
120-
Object entity = linker.apply(source.entity(), target.entity());
121-
if (entity != null) {
122-
AggregateEntityCacheKey cacheKey = AggregateEntityCacheKey.of(source.entityKey());
123-
entityCache.replace(cacheKey, entity);
124-
associationCandidate.replace(
125-
source.pathKey(), new AggregateEntityPoolEntry(source.entityKey(), entity));
117+
Object newEntity = linker.apply(source.entity(), target.entity());
118+
if (newEntity != null && newEntity != source.entity()) {
119+
entityCache.replace(source.entityId(), newEntity);
120+
entityPool.replace(new AssociationEntityPoolEntry(source.entityKey(), newEntity));
126121
}
127122
}
128123
}

doma-core/src/main/java/org/seasar/doma/jdbc/aggregate/AggregateEntityKey.java renamed to doma-core/src/main/java/org/seasar/doma/jdbc/aggregate/AssociationEntityKey.java

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,15 @@
1717

1818
import java.util.List;
1919
import java.util.Objects;
20-
import org.seasar.doma.jdbc.entity.EntityType;
20+
import org.seasar.doma.jdbc.EntityId;
2121

22-
public record AggregateEntityKey(AggregatePathKey pathKey, List<?> items) {
23-
public AggregateEntityKey {
22+
public record AssociationEntityKey(AssociationPathKey pathKey, List<?> items) {
23+
public AssociationEntityKey {
2424
Objects.requireNonNull(pathKey);
2525
Objects.requireNonNull(items);
2626
}
2727

28-
public String propertyPath() {
29-
return pathKey.propertyPath();
30-
}
31-
32-
public EntityType<?> entityType() {
33-
return pathKey.entityType();
28+
public EntityId entityId() {
29+
return new EntityId(pathKey.entityType(), items);
3430
}
3531
}

doma-core/src/main/java/org/seasar/doma/jdbc/aggregate/AggregateEntityPool.java renamed to doma-core/src/main/java/org/seasar/doma/jdbc/aggregate/AssociationEntityPool.java

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,26 @@
1515
*/
1616
package org.seasar.doma.jdbc.aggregate;
1717

18-
import java.util.ArrayList;
19-
import java.util.Iterator;
20-
import java.util.List;
18+
import java.util.HashMap;
19+
import java.util.Map;
2120
import java.util.Objects;
2221

23-
public class AggregateEntityPool implements Iterable<AggregateEntityPoolEntry> {
24-
private final List<AggregateEntityPoolEntry> entities = new ArrayList<>();
22+
public class AssociationEntityPool {
23+
private final Map<AssociationPathKey, AssociationEntityPoolEntry> entries = new HashMap<>();
2524

26-
public void add(AggregateEntityPoolEntry entry) {
25+
public void add(AssociationEntityPoolEntry entry) {
2726
Objects.requireNonNull(entry);
28-
entities.add(entry);
27+
entries.put(entry.pathKey(), entry);
2928
}
3029

31-
@SuppressWarnings("NullableProblems")
32-
@Override
33-
public Iterator<AggregateEntityPoolEntry> iterator() {
34-
return entities.iterator();
30+
public AssociationEntityPoolEntry get(AssociationPathKey pathKey) {
31+
Objects.requireNonNull(pathKey);
32+
return entries.get(pathKey);
33+
}
34+
35+
public void replace(AssociationEntityPoolEntry entry) {
36+
Objects.requireNonNull(entry);
37+
Objects.requireNonNull(entry);
38+
entries.replace(entry.pathKey(), entry);
3539
}
3640
}

doma-core/src/main/java/org/seasar/doma/jdbc/aggregate/AggregateEntityPoolEntry.java renamed to doma-core/src/main/java/org/seasar/doma/jdbc/aggregate/AssociationEntityPoolEntry.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,19 @@
1616
package org.seasar.doma.jdbc.aggregate;
1717

1818
import java.util.Objects;
19+
import org.seasar.doma.jdbc.EntityId;
1920

20-
public record AggregateEntityPoolEntry(AggregateEntityKey entityKey, Object entity) {
21-
public AggregateEntityPoolEntry {
21+
public record AssociationEntityPoolEntry(AssociationEntityKey entityKey, Object entity) {
22+
public AssociationEntityPoolEntry {
2223
Objects.requireNonNull(entityKey);
2324
Objects.requireNonNull(entity);
2425
}
2526

26-
public AggregatePathKey pathKey() {
27+
public AssociationPathKey pathKey() {
2728
return entityKey.pathKey();
2829
}
30+
31+
public EntityId entityId() {
32+
return entityKey.entityId();
33+
}
2934
}
Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -21,45 +21,46 @@
2121
import java.util.Set;
2222
import org.seasar.doma.internal.jdbc.command.AbstractIterationHandler;
2323
import org.seasar.doma.internal.jdbc.command.ResultListCallback;
24+
import org.seasar.doma.jdbc.EntityId;
2425
import org.seasar.doma.jdbc.ObjectProvider;
2526
import org.seasar.doma.jdbc.entity.EntityType;
2627
import org.seasar.doma.jdbc.query.SelectQuery;
2728

2829
/**
29-
* Handles the iteration of {@link AggregateEntityPool} results from a query execution and manages
30+
* Handles the iteration of {@link AssociationEntityPool} results from a query execution and manages
3031
* the creation and configuration of object providers used to process the results.
3132
*/
32-
public class AggregateEntityPoolIterationHandler
33-
extends AbstractIterationHandler<AggregateEntityPool, List<AggregateEntityPool>> {
33+
public class AssociationEntityPoolIterationHandler
34+
extends AbstractIterationHandler<AssociationEntityPool, List<AssociationEntityPool>> {
3435

35-
private final EntityType<?> entityType;
36+
private final EntityType<?> rootEntityType;
3637
private final AggregateStrategyType aggregateStrategyType;
3738
private final boolean resultMappingEnsured;
38-
private final Set<AggregateEntityCacheKey> rootEntityKeys;
39-
private final Map<AggregateEntityCacheKey, Object> entityCache;
39+
private final Set<EntityId> rootEntityIds;
40+
private final Map<EntityId, Object> entityCache;
4041

41-
public AggregateEntityPoolIterationHandler(
42-
EntityType<?> entityType,
42+
public AssociationEntityPoolIterationHandler(
43+
EntityType<?> rootEntityType,
4344
AggregateStrategyType aggregateStrategyType,
4445
boolean resultMappingEnsured,
45-
Set<AggregateEntityCacheKey> rootEntityKeys,
46-
Map<AggregateEntityCacheKey, Object> entityCache) {
46+
Set<EntityId> rootEntityIds,
47+
Map<EntityId, Object> entityCache) {
4748
super(new ResultListCallback<>());
48-
this.entityType = Objects.requireNonNull(entityType);
49+
this.rootEntityType = Objects.requireNonNull(rootEntityType);
4950
this.aggregateStrategyType = Objects.requireNonNull(aggregateStrategyType);
5051
this.resultMappingEnsured = resultMappingEnsured;
51-
this.rootEntityKeys = Objects.requireNonNull(rootEntityKeys);
52+
this.rootEntityIds = Objects.requireNonNull(rootEntityIds);
5253
this.entityCache = Objects.requireNonNull(entityCache);
5354
}
5455

5556
@Override
56-
protected ObjectProvider<AggregateEntityPool> createObjectProvider(SelectQuery query) {
57-
return new AggregateEntityPoolProvider(
58-
entityType,
57+
protected ObjectProvider<AssociationEntityPool> createObjectProvider(SelectQuery query) {
58+
return new AssociationEntityPoolProvider(
59+
rootEntityType,
5960
aggregateStrategyType,
6061
query,
6162
resultMappingEnsured,
62-
rootEntityKeys,
63+
rootEntityIds,
6364
entityCache);
6465
}
6566
}

0 commit comments

Comments
 (0)