Skip to content

Commit 43a9eb1

Browse files
committed
Support to associate immutable entities
1 parent e388ab9 commit 43a9eb1

File tree

8 files changed

+362
-18
lines changed

8 files changed

+362
-18
lines changed

doma-core/src/main/java/org/seasar/doma/jdbc/criteria/command/AssociateCommand.java

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@
66
import java.util.List;
77
import java.util.Map;
88
import java.util.Objects;
9-
import java.util.function.BiConsumer;
9+
import java.util.function.BiFunction;
1010
import org.seasar.doma.internal.util.Pair;
1111
import org.seasar.doma.jdbc.command.Command;
1212
import org.seasar.doma.jdbc.command.SelectCommand;
13+
import org.seasar.doma.jdbc.criteria.context.AssociationPair;
1314
import org.seasar.doma.jdbc.criteria.context.SelectContext;
1415
import org.seasar.doma.jdbc.criteria.metamodel.EntityMetamodel;
1516
import org.seasar.doma.jdbc.entity.EntityType;
@@ -37,7 +38,7 @@ public List<ENTITY> execute() {
3738
query, new EntityPoolIterationHandler(context.getProjectionEntityMetamodels()));
3839
List<EntityPool> entityPools = command.execute();
3940
for (EntityPool entityPool : entityPools) {
40-
Map<EntityMetamodel<?>, Object> associationCandidate = new LinkedHashMap<>();
41+
Map<EntityMetamodel<?>, Pair<EntityKey, Object>> associationCandidate = new LinkedHashMap<>();
4142
for (Map.Entry<EntityKey, EntityData> e : entityPool.entrySet()) {
4243
EntityKey key = e.getKey();
4344
EntityData data = e.getValue();
@@ -53,9 +54,9 @@ public List<ENTITY> execute() {
5354
}
5455
return newEntity;
5556
});
56-
associationCandidate.put(key.getEntityMetamodel(), entity);
57+
associationCandidate.put(key.getEntityMetamodel(), new Pair<>(key, entity));
5758
}
58-
associate(associationCandidate);
59+
associate(cache, associationCandidate);
5960
}
6061
return (List<ENTITY>)
6162
cache.entrySet().stream()
@@ -64,17 +65,30 @@ public List<ENTITY> execute() {
6465
.collect(toList());
6566
}
6667

67-
private void associate(Map<EntityMetamodel<?>, Object> associationCandidate) {
68-
for (Map.Entry<Pair<EntityMetamodel<?>, EntityMetamodel<?>>, BiConsumer<Object, Object>> e :
69-
context.associations.entrySet()) {
70-
Pair<EntityMetamodel<?>, EntityMetamodel<?>> pair = e.getKey();
71-
BiConsumer<Object, Object> associator = e.getValue();
72-
Object entity1 = associationCandidate.get(pair.fst);
73-
Object entity2 = associationCandidate.get(pair.snd);
74-
if (entity1 == null || entity2 == null) {
68+
private void associate(
69+
Map<EntityKey, Object> cache,
70+
Map<EntityMetamodel<?>, Pair<EntityKey, Object>> associationCandidate) {
71+
for (Map.Entry<
72+
Pair<EntityMetamodel<?>, EntityMetamodel<?>>,
73+
BiFunction<Object, Object, AssociationPair<?, ?>>>
74+
e : context.associations.entrySet()) {
75+
Pair<EntityMetamodel<?>, EntityMetamodel<?>> metamodelPair = e.getKey();
76+
BiFunction<Object, Object, AssociationPair<?, ?>> associator = e.getValue();
77+
Pair<EntityKey, Object> keyAndEntity1 = associationCandidate.get(metamodelPair.fst);
78+
Pair<EntityKey, Object> keyAndEntity2 = associationCandidate.get(metamodelPair.snd);
79+
if (keyAndEntity1 == null || keyAndEntity2 == null) {
7580
continue;
7681
}
77-
associator.accept(entity1, entity2);
82+
AssociationPair<?, ?> associationPair =
83+
associator.apply(keyAndEntity1.snd, keyAndEntity2.snd);
84+
if (associationPair != null) {
85+
cache.replace(keyAndEntity1.fst, associationPair.getFirst());
86+
cache.replace(keyAndEntity2.fst, associationPair.getSecond());
87+
associationCandidate.replace(
88+
metamodelPair.fst, new Pair<>(keyAndEntity1.fst, associationPair.getFirst()));
89+
associationCandidate.replace(
90+
metamodelPair.snd, new Pair<>(keyAndEntity2.fst, associationPair.getSecond()));
91+
}
7892
}
7993
}
8094

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package org.seasar.doma.jdbc.criteria.context;
2+
3+
import java.util.Objects;
4+
5+
public class AssociationPair<ENTITY1, ENTITY2> {
6+
7+
private final ENTITY1 first;
8+
private final ENTITY2 second;
9+
10+
public AssociationPair(ENTITY1 first, ENTITY2 second) {
11+
this.first = Objects.requireNonNull(first);
12+
this.second = Objects.requireNonNull(second);
13+
}
14+
15+
public ENTITY1 getFirst() {
16+
return first;
17+
}
18+
19+
public ENTITY2 getSecond() {
20+
return second;
21+
}
22+
}

doma-core/src/main/java/org/seasar/doma/jdbc/criteria/context/SelectContext.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import java.util.List;
99
import java.util.Map;
1010
import java.util.Objects;
11-
import java.util.function.BiConsumer;
11+
import java.util.function.BiFunction;
1212
import java.util.stream.Stream;
1313
import org.seasar.doma.internal.util.Pair;
1414
import org.seasar.doma.jdbc.criteria.metamodel.EntityMetamodel;
@@ -28,7 +28,9 @@ public class SelectContext implements Context {
2828
public Integer limit;
2929
public Integer offset;
3030
public ForUpdate forUpdate = new ForUpdate(ForUpdateOption.none());
31-
public final Map<Pair<EntityMetamodel<?>, EntityMetamodel<?>>, BiConsumer<Object, Object>>
31+
public final Map<
32+
Pair<EntityMetamodel<?>, EntityMetamodel<?>>,
33+
BiFunction<Object, Object, AssociationPair<?, ?>>>
3234
associations = new LinkedHashMap<>();
3335
public final SelectSettings settings = new SelectSettings();
3436

doma-core/src/main/java/org/seasar/doma/jdbc/criteria/declaration/SelectFromDeclaration.java

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@
77
import java.util.Objects;
88
import java.util.Set;
99
import java.util.function.BiConsumer;
10+
import java.util.function.BiFunction;
1011
import java.util.function.Consumer;
1112
import org.seasar.doma.DomaException;
1213
import org.seasar.doma.internal.util.Pair;
14+
import org.seasar.doma.jdbc.criteria.context.AssociationPair;
1315
import org.seasar.doma.jdbc.criteria.context.ForUpdate;
1416
import org.seasar.doma.jdbc.criteria.context.Join;
1517
import org.seasar.doma.jdbc.criteria.context.JoinKind;
@@ -142,7 +144,6 @@ public void selectTo(
142144
new Projection.EntityMetamodels(entityMetamodel, new ArrayList<>(projectionTargets));
143145
}
144146

145-
@SuppressWarnings("unchecked")
146147
public <ENTITY1, ENTITY2> void associate(
147148
EntityMetamodel<ENTITY1> first,
148149
EntityMetamodel<ENTITY2> second,
@@ -152,6 +153,26 @@ public <ENTITY1, ENTITY2> void associate(
152153
Objects.requireNonNull(second);
153154
Objects.requireNonNull(associator);
154155
Objects.requireNonNull(option);
156+
associateAndReplace(
157+
first,
158+
second,
159+
(entity1, entity2) -> {
160+
associator.accept(entity1, entity2);
161+
return null;
162+
},
163+
option);
164+
}
165+
166+
@SuppressWarnings("unchecked")
167+
public <ENTITY1, ENTITY2> void associateAndReplace(
168+
EntityMetamodel<ENTITY1> first,
169+
EntityMetamodel<ENTITY2> second,
170+
BiFunction<ENTITY1, ENTITY2, AssociationPair<ENTITY1, ENTITY2>> associator,
171+
AssociationOption option) {
172+
Objects.requireNonNull(first);
173+
Objects.requireNonNull(second);
174+
Objects.requireNonNull(associator);
175+
Objects.requireNonNull(option);
155176
if (!context.getEntityMetamodels().contains(first)) {
156177
if (option == AssociationOption.Kind.MANDATORY) {
157178
throw new DomaException(Message.DOMA6001, "first");
@@ -164,7 +185,8 @@ public <ENTITY1, ENTITY2> void associate(
164185
}
165186
return;
166187
}
167-
//noinspection unchecked
168-
context.associations.put(new Pair<>(first, second), (BiConsumer<Object, Object>) associator);
188+
context.associations.put(
189+
new Pair<>(first, second),
190+
(entity1, entity2) -> associator.apply((ENTITY1) entity1, (ENTITY2) entity2));
169191
}
170192
}

doma-core/src/main/java/org/seasar/doma/jdbc/criteria/statement/EntityqlSelectStarting.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@
44
import java.util.List;
55
import java.util.Objects;
66
import java.util.function.BiConsumer;
7+
import java.util.function.BiFunction;
78
import java.util.function.Consumer;
89
import org.seasar.doma.jdbc.Config;
910
import org.seasar.doma.jdbc.command.Command;
11+
import org.seasar.doma.jdbc.criteria.context.AssociationPair;
1012
import org.seasar.doma.jdbc.criteria.declaration.JoinDeclaration;
1113
import org.seasar.doma.jdbc.criteria.declaration.OrderByNameDeclaration;
1214
import org.seasar.doma.jdbc.criteria.declaration.SelectFromDeclaration;
@@ -82,6 +84,30 @@ public <ENTITY1, ENTITY2> EntityqlSelectStarting<ENTITY> associate(
8284
return this;
8385
}
8486

87+
public <ENTITY1, ENTITY2> EntityqlSelectStarting<ENTITY> associateAndReplace(
88+
EntityMetamodel<ENTITY1> first,
89+
EntityMetamodel<ENTITY2> second,
90+
BiFunction<ENTITY1, ENTITY2, AssociationPair<ENTITY1, ENTITY2>> associator) {
91+
Objects.requireNonNull(first);
92+
Objects.requireNonNull(second);
93+
Objects.requireNonNull(associator);
94+
declaration.associateAndReplace(first, second, associator, AssociationOption.mandatory());
95+
return this;
96+
}
97+
98+
public <ENTITY1, ENTITY2> EntityqlSelectStarting<ENTITY> associateAndReplace(
99+
EntityMetamodel<ENTITY1> first,
100+
EntityMetamodel<ENTITY2> second,
101+
BiFunction<ENTITY1, ENTITY2, AssociationPair<ENTITY1, ENTITY2>> associator,
102+
AssociationOption option) {
103+
Objects.requireNonNull(first);
104+
Objects.requireNonNull(second);
105+
Objects.requireNonNull(associator);
106+
Objects.requireNonNull(option);
107+
declaration.associateAndReplace(first, second, associator, option);
108+
return this;
109+
}
110+
85111
public EntityqlSelectStarting<ENTITY> where(Consumer<WhereDeclaration> block) {
86112
Objects.requireNonNull(block);
87113
declaration.where(block);
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package example;
2+
3+
import org.seasar.doma.Entity;
4+
import org.seasar.doma.Id;
5+
import org.seasar.doma.Metamodel;
6+
import org.seasar.doma.Table;
7+
import org.seasar.doma.Version;
8+
9+
@Entity(immutable = true, metamodel = @Metamodel)
10+
@Table(name = "DEPARTMENT")
11+
public class Dept {
12+
13+
@Id private final Integer departmentId;
14+
private final Integer departmentNo;
15+
private final String departmentName;
16+
private final String location;
17+
@Version private final Integer version;
18+
19+
public Dept(
20+
Integer departmentId,
21+
Integer departmentNo,
22+
String departmentName,
23+
String location,
24+
Integer version) {
25+
this.departmentId = departmentId;
26+
this.departmentNo = departmentNo;
27+
this.departmentName = departmentName;
28+
this.location = location;
29+
this.version = version;
30+
}
31+
32+
public Integer getDepartmentId() {
33+
return departmentId;
34+
}
35+
36+
public Integer getDepartmentNo() {
37+
return departmentNo;
38+
}
39+
40+
public String getDepartmentName() {
41+
return departmentName;
42+
}
43+
44+
public String getLocation() {
45+
return location;
46+
}
47+
48+
public Integer getVersion() {
49+
return version;
50+
}
51+
}
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
package example;
2+
3+
import java.time.LocalDate;
4+
import org.seasar.doma.Entity;
5+
import org.seasar.doma.Id;
6+
import org.seasar.doma.Metamodel;
7+
import org.seasar.doma.Table;
8+
import org.seasar.doma.Transient;
9+
import org.seasar.doma.Version;
10+
11+
@Entity(immutable = true, metamodel = @Metamodel)
12+
@Table(name = "EMPLOYEE")
13+
public class Emp {
14+
15+
@Id private final Integer employeeId;
16+
private final Integer employeeNo;
17+
private final String employeeName;
18+
private final Integer managerId;
19+
private final LocalDate hiredate;
20+
private final Salary salary;
21+
private final Integer departmentId;
22+
private final Integer addressId;
23+
@Version private final Integer version;
24+
@Transient private final Dept department;
25+
@Transient private final Emp manager;
26+
27+
public Emp(
28+
Integer employeeId,
29+
Integer employeeNo,
30+
String employeeName,
31+
Integer managerId,
32+
LocalDate hiredate,
33+
Salary salary,
34+
Integer departmentId,
35+
Integer addressId,
36+
Integer version) {
37+
this(
38+
employeeId,
39+
employeeNo,
40+
employeeName,
41+
managerId,
42+
hiredate,
43+
salary,
44+
departmentId,
45+
addressId,
46+
version,
47+
null,
48+
null);
49+
}
50+
51+
public Emp(
52+
Integer employeeId,
53+
Integer employeeNo,
54+
String employeeName,
55+
Integer managerId,
56+
LocalDate hiredate,
57+
Salary salary,
58+
Integer departmentId,
59+
Integer addressId,
60+
Integer version,
61+
Dept department,
62+
Emp manager) {
63+
this.employeeId = employeeId;
64+
this.employeeNo = employeeNo;
65+
this.employeeName = employeeName;
66+
this.managerId = managerId;
67+
this.hiredate = hiredate;
68+
this.salary = salary;
69+
this.departmentId = departmentId;
70+
this.addressId = addressId;
71+
this.version = version;
72+
this.department = department;
73+
this.manager = manager;
74+
}
75+
76+
public Integer getEmployeeId() {
77+
return employeeId;
78+
}
79+
80+
public Integer getEmployeeNo() {
81+
return employeeNo;
82+
}
83+
84+
public String getEmployeeName() {
85+
return employeeName;
86+
}
87+
88+
public Integer getManagerId() {
89+
return managerId;
90+
}
91+
92+
public LocalDate getHiredate() {
93+
return hiredate;
94+
}
95+
96+
public Salary getSalary() {
97+
return salary;
98+
}
99+
100+
public Integer getDepartmentId() {
101+
return departmentId;
102+
}
103+
104+
public Integer getAddressId() {
105+
return addressId;
106+
}
107+
108+
public Integer getVersion() {
109+
return version;
110+
}
111+
112+
public Dept getDepartment() {
113+
return department;
114+
}
115+
116+
public Emp getManager() {
117+
return manager;
118+
}
119+
}

0 commit comments

Comments
 (0)