From 1e14b93be4d2ff93c349316a641330fbed4a3ab4 Mon Sep 17 00:00:00 2001 From: Liu Rui Date: Fri, 14 Aug 2026 09:34:45 +0800 Subject: [PATCH 1/4] =?UTF-8?q?test:=20=E9=94=81=E5=AE=9A=E5=BC=95?= =?UTF-8?q?=E7=94=A8=E8=AF=BB=E5=8F=96=E6=89=B9=E9=87=8F=E5=A5=91=E7=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...DynamicEntityServiceReferenceReadTest.java | 27 +++-- .../PlatformReferenceLoadResolverTest.java | 111 ++++++++++++++++++ 2 files changed, 129 insertions(+), 9 deletions(-) create mode 100644 muyun-platform/src/test/java/net/ximatai/muyun/spring/platform/reference/PlatformReferenceLoadResolverTest.java diff --git a/muyun-dynamic/src/test/java/net/ximatai/muyun/spring/dynamic/runtime/DynamicEntityServiceReferenceReadTest.java b/muyun-dynamic/src/test/java/net/ximatai/muyun/spring/dynamic/runtime/DynamicEntityServiceReferenceReadTest.java index 0e83240e..5940cc86 100644 --- a/muyun-dynamic/src/test/java/net/ximatai/muyun/spring/dynamic/runtime/DynamicEntityServiceReferenceReadTest.java +++ b/muyun-dynamic/src/test/java/net/ximatai/muyun/spring/dynamic/runtime/DynamicEntityServiceReferenceReadTest.java @@ -140,24 +140,33 @@ void shouldPopulateDynamicReferencedByCollection() { .referencedBys(List.of(new EntityReferencedByDefinition("classroom", "member", "classroomId", "members"))) .build(); new ModuleDefinitionValidator().validate(module); - DynamicRecord classroomRecord = new DynamicRecord(classroom); - classroomRecord.setId("classroom-1"); - DynamicRecord memberRecord = new DynamicRecord(member); - memberRecord.setId("member-1"); - memberRecord.setValue("classroomId", "classroom-1"); + DynamicRecord firstClassroom = new DynamicRecord(classroom); + firstClassroom.setId("classroom-1"); + DynamicRecord secondClassroom = new DynamicRecord(classroom); + secondClassroom.setId("classroom-2"); + DynamicRecord firstMember = new DynamicRecord(member); + firstMember.setId("member-1"); + firstMember.setValue("classroomId", "classroom-1"); + DynamicRecord secondMember = new DynamicRecord(member); + secondMember.setId("member-2"); + secondMember.setValue("classroomId", "classroom-2"); DynamicRecordDao classroomDao = mock(DynamicRecordDao.class); when(classroomDao.getEntity()).thenReturn(classroom); - when(classroomDao.query(any(Criteria.class), any(PageRequest.class), any(Sort[].class))).thenReturn(List.of(classroomRecord)); + when(classroomDao.query(any(Criteria.class), any(PageRequest.class), any(Sort[].class))) + .thenReturn(List.of(firstClassroom, secondClassroom)); DynamicEntityService memberService = mock(DynamicEntityService.class); - when(memberService.list(any(Criteria.class))).thenReturn(List.of(memberRecord)); + when(memberService.list(any(Criteria.class))).thenReturn(List.of(firstMember, secondMember)); DynamicEntityService service = new DynamicEntityService(classroomDao, "education.school", DynamicRecordLifecycle.NONE, module, alias -> "member".equals(alias) ? memberService : null, ignored -> { throw new IllegalStateException("targets are not read"); }, null, DynamicFieldValueValidator.NONE, FieldCryptoProvider.UNAVAILABLE, FieldSigner.UNAVAILABLE, new PlatformTimeService()); - assertThat((List) service.list(Criteria.of(), PageRequest.of(1, 20)).getFirst().getValue("members")) - .containsExactly(memberRecord); + List classrooms = service.list(Criteria.of(), PageRequest.of(1, 20)); + + assertThat((List) classrooms.getFirst().getValue("members")).containsExactly(firstMember); + assertThat((List) classrooms.get(1).getValue("members")).containsExactly(secondMember); + verify(memberService, times(1)).list(any(Criteria.class)); } @Test diff --git a/muyun-platform/src/test/java/net/ximatai/muyun/spring/platform/reference/PlatformReferenceLoadResolverTest.java b/muyun-platform/src/test/java/net/ximatai/muyun/spring/platform/reference/PlatformReferenceLoadResolverTest.java new file mode 100644 index 00000000..f4c5e45c --- /dev/null +++ b/muyun-platform/src/test/java/net/ximatai/muyun/spring/platform/reference/PlatformReferenceLoadResolverTest.java @@ -0,0 +1,111 @@ +package net.ximatai.muyun.spring.platform.reference; + +import net.ximatai.muyun.spring.ability.BaseDao; +import net.ximatai.muyun.spring.ability.CrudAbility; +import net.ximatai.muyun.spring.ability.reference.ReferenceAbility; +import net.ximatai.muyun.spring.ability.reference.ReferenceLoad; +import net.ximatai.muyun.spring.ability.reference.ReferenceReadFacade; +import net.ximatai.muyun.spring.ability.reference.ReferenceTo; +import net.ximatai.muyun.spring.common.model.standard.StandardEntity; +import net.ximatai.muyun.spring.common.model.standard.StandardTitledEntity; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; + +class PlatformReferenceLoadResolverTest { + @Test + void shouldBatchPopulateDeclaredReferenceLoadFactsThroughDomainReadFacade() { + OrderRecord first = order("order-1", "customer-1"); + OrderRecord second = order("order-2", "customer-2"); + CustomerAbility customers = new CustomerAbility(); + ModelAbility orders = new ModelAbility(OrderRecord.class, "test.order"); + ReferenceReadFacade reads = new ReferenceReadFacade( + new PlatformReferenceLoadResolver(new StaticAbilityCatalog(List.of(orders, customers)))); + + reads.enrich(orders, List.of(first, second)); + + assertThat(customers.requests).containsExactly(List.of("customer-1", "customer-2")); + assertThat(first.customerTitle).isEqualTo("客户一"); + assertThat(second.customerTitle).isEqualTo("客户二"); + } + + private static OrderRecord order(String id, String customerId) { + OrderRecord record = new OrderRecord(); + record.setId(id); + record.customerId = customerId; + return record; + } + + private static final class OrderRecord extends StandardEntity { + @ReferenceTo(target = CustomerService.class) + private String customerId; + + @ReferenceLoad(source = "customerId", field = "title") + private transient String customerTitle; + } + + private static final class CustomerRecord extends StandardTitledEntity { + } + + public static final class CustomerService { + public static final String MODULE_ALIAS = "test.customer"; + } + + private static final class ModelAbility implements CrudAbility { + private final Class modelClass; + private final String moduleAlias; + + private ModelAbility(Class modelClass, String moduleAlias) { + this.modelClass = modelClass; + this.moduleAlias = moduleAlias; + } + + @Override + public Class modelClass() { + return modelClass; + } + + @Override + public BaseDao getDao() { + throw new UnsupportedOperationException(); + } + + @Override + public String getModuleAlias() { + return moduleAlias; + } + } + + private static final class CustomerAbility implements ReferenceAbility { + private final List> requests = new ArrayList<>(); + + @Override + public Class modelClass() { + return CustomerRecord.class; + } + + @Override + public BaseDao getDao() { + throw new UnsupportedOperationException(); + } + + @Override + public String getModuleAlias() { + return CustomerService.MODULE_ALIAS; + } + + @Override + public Map> projections(Collection ids, Collection fields) { + requests.add(List.copyOf(ids)); + assertThat(fields).containsExactly("title"); + return Map.of( + "customer-1", Map.of("title", "客户一"), + "customer-2", Map.of("title", "客户二")); + } + } +} From 07cda4da1dd0444b467c387e519a5578f117d5e3 Mon Sep 17 00:00:00 2001 From: Liu Rui Date: Fri, 14 Aug 2026 09:38:16 +0800 Subject: [PATCH 2/4] =?UTF-8?q?test:=20=E5=AF=B9=E9=BD=90=E5=BC=95?= =?UTF-8?q?=E7=94=A8=E8=AF=BB=E5=8F=96=E8=B7=A8=E5=85=A5=E5=8F=A3=E8=AF=AD?= =?UTF-8?q?=E4=B9=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...erenceReadProjectionPostProcessorTest.java | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/muyun-platform-web/src/test/java/net/ximatai/muyun/spring/platform/web/ReferenceReadProjectionPostProcessorTest.java b/muyun-platform-web/src/test/java/net/ximatai/muyun/spring/platform/web/ReferenceReadProjectionPostProcessorTest.java index bd8a0fc2..b1f6b58b 100644 --- a/muyun-platform-web/src/test/java/net/ximatai/muyun/spring/platform/web/ReferenceReadProjectionPostProcessorTest.java +++ b/muyun-platform-web/src/test/java/net/ximatai/muyun/spring/platform/web/ReferenceReadProjectionPostProcessorTest.java @@ -1,12 +1,18 @@ package net.ximatai.muyun.spring.platform.web; import net.ximatai.muyun.spring.ability.PlatformAbilityRuntime; +import net.ximatai.muyun.spring.ability.CrudAbility; import net.ximatai.muyun.spring.ability.reference.ReferenceAbility; import net.ximatai.muyun.spring.ability.reference.ReferenceLoad; +import net.ximatai.muyun.spring.ability.reference.ReferenceReadFacade; import net.ximatai.muyun.spring.ability.reference.ReferenceSummary; import net.ximatai.muyun.spring.ability.reference.ReferenceHop; import net.ximatai.muyun.spring.ability.reference.ReferenceTo; import net.ximatai.muyun.spring.ability.reference.ReferenceTarget; +import net.ximatai.muyun.spring.common.model.standard.StandardEntity; +import net.ximatai.muyun.spring.common.model.standard.StandardTitledEntity; +import net.ximatai.muyun.spring.platform.reference.PlatformReferenceLoadResolver; +import net.ximatai.muyun.spring.platform.reference.StaticAbilityCatalog; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; @@ -15,7 +21,9 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -51,6 +59,34 @@ void shouldBatchEnrichStaticRecordsFromADynamicReferenceTarget() { verify(target).projections(List.of("customer-1", "customer-2"), List.of("title", "level")); } + @Test + void shouldKeepDeclaredReferenceLoadEqualBetweenDomainFacadeAndListProjection() { + DomainOrder domainOrder = new DomainOrder(); + domainOrder.setId("order-1"); + domainOrder.customerId = "customer-1"; + @SuppressWarnings("unchecked") CrudAbility orders = mock(CrudAbility.class); + doReturn(DomainOrder.class).when(orders).modelClass(); + when(orders.getModuleAlias()).thenReturn("crm.order"); + @SuppressWarnings("unchecked") ReferenceAbility customer = mock(ReferenceAbility.class); + doReturn(CustomerRecord.class).when(customer).modelClass(); + when(customer.getModuleAlias()).thenReturn("crm.customer"); + when(customer.projections(eq(List.of("customer-1")), eq(List.of("title")))) + .thenReturn(Map.of("customer-1", Map.of("title", "客户一"))); + ReferenceTarget customerTarget = ReferenceTarget.of("crm", "customer"); + PlatformAbilityRuntime.configureReferenceTargetResolver(target -> customerTarget.equals(target) + ? java.util.Optional.of(customer) : java.util.Optional.empty()); + + new ReferenceReadFacade(new PlatformReferenceLoadResolver( + new StaticAbilityCatalog(List.of(orders, customer)))).enrich(orders, List.of(domainOrder)); + List> listed = ReferenceReadProjectionPostProcessor.apply(DomainOrder.class, + List.of(Map.of("id", "order-1", "customerId", "customer-1"))); + + assertThat(domainOrder.customerTitle).isEqualTo("客户一"); + assertThat(listed).containsExactly(Map.of( + "id", "order-1", "customerId", "customer-1", "customerTitle", "客户一")); + verify(customer, times(2)).projections(List.of("customer-1"), List.of("title")); + } + @Test void shouldStripInternalReadFieldsEvenWhenNoReferenceProjectionIsRequested() { List> result = ReferenceReadProjectionPostProcessor.apply(PlainRecord.class, List.of( @@ -136,6 +172,17 @@ private static final class StaticOrder { private transient String customerLevel; } + private static final class DomainOrder extends StandardEntity { + @ReferenceTo(moduleAlias = "crm", entityAlias = "customer") + private String customerId; + + @ReferenceLoad(source = "customerId", field = "title") + private transient String customerTitle; + } + + private static final class CustomerRecord extends StandardTitledEntity { + } + private static final class PlainRecord { private String title; } From 257172d67ba96a73d504cf6be9bf86b49f09711e Mon Sep 17 00:00:00 2001 From: Liu Rui Date: Fri, 14 Aug 2026 10:01:33 +0800 Subject: [PATCH 3/4] =?UTF-8?q?feat:=20=E8=87=AA=E5=8A=A8=E5=9B=9E?= =?UTF-8?q?=E5=A1=AB=E9=9D=99=E6=80=81=E5=88=97=E8=A1=A8=E5=BC=95=E7=94=A8?= =?UTF-8?q?=E4=BA=8B=E5=AE=9E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../STATIC_REFERENCE_READ_PROJECTION.md | 4 +++ .../muyun/spring/ability/CrudAbility.java | 20 +++++++++-- .../ability/PlatformAbilityDispatcher.java | 4 +++ .../security/FieldProtectionAbility.java | 9 +++-- .../spring/ability/AbilityContractTest.java | 34 +++++++++++++++++++ 5 files changed, 66 insertions(+), 5 deletions(-) diff --git a/docs/architecture/STATIC_REFERENCE_READ_PROJECTION.md b/docs/architecture/STATIC_REFERENCE_READ_PROJECTION.md index 899bf2b0..8ab0d553 100644 --- a/docs/architecture/STATIC_REFERENCE_READ_PROJECTION.md +++ b/docs/architecture/STATIC_REFERENCE_READ_PROJECTION.md @@ -113,6 +113,10 @@ private transient String cStatus; 生命周期等额外业务信息仍由领域 facade 显式组合。`PlatformAbilityRuntime` 是平台内部的装配入口,普通业务 service 不应直接依赖它。 +静态 `CrudAbility` 的标准 `list(...)` 与 `pageQuery(...)` 会自动批量回填声明的 `@ReferenceLoad`, +因此普通列表和分页业务代码不需要再调用读取门面。列表默认不自动回填 `@ReferencedBy`,避免一对多集合随 +分页记录膨胀;单条读取和明确的领域聚合仍按各自读取边界处理。 + ## 读投影声明 当前模块对外可带出的关联字段声明在 service 上: diff --git a/muyun-ability/src/main/java/net/ximatai/muyun/spring/ability/CrudAbility.java b/muyun-ability/src/main/java/net/ximatai/muyun/spring/ability/CrudAbility.java index bbc597d6..bf365cbc 100644 --- a/muyun-ability/src/main/java/net/ximatai/muyun/spring/ability/CrudAbility.java +++ b/muyun-ability/src/main/java/net/ximatai/muyun/spring/ability/CrudAbility.java @@ -215,15 +215,29 @@ default int deleteBatch(Collection ids, DeletionContext deletionContext) @PlatformOperation(PlatformAction.QUERY) default PageResult pageQuery(Criteria criteria, PageRequest pageRequest, Sort... sorts) { - return getDao().pageQuery(activeCriteria(criteria), pageRequest, sorts); + PageResult result = getDao().pageQuery(activeCriteria(criteria), pageRequest, sorts); + populateDeclaredReferenceLoads(result.getRecords()); + return result; } default List list(Criteria criteria, PageRequest pageRequest, Sort... sorts) { - return getDao().query(activeCriteria(criteria), pageRequest, sorts); + List records = getDao().query(activeCriteria(criteria), pageRequest, sorts); + populateDeclaredReferenceLoads(records); + return records; } default List list(Criteria criteria, Sort... sorts) { - return getDao().list(activeCriteria(criteria), sorts); + List records = getDao().list(activeCriteria(criteria), sorts); + populateDeclaredReferenceLoads(records); + return records; + } + + /** + * Internal post-read step shared by standard list reads and ability decorators. + * Ordinary services do not call this directly; standard query methods invoke it automatically. + */ + default void populateDeclaredReferenceLoads(Collection records) { + PlatformAbilityDispatcher.populateReferenceLoads(this, records == null ? List.of() : records); } default long count(Criteria criteria) { diff --git a/muyun-ability/src/main/java/net/ximatai/muyun/spring/ability/PlatformAbilityDispatcher.java b/muyun-ability/src/main/java/net/ximatai/muyun/spring/ability/PlatformAbilityDispatcher.java index 233bc808..2838333e 100644 --- a/muyun-ability/src/main/java/net/ximatai/muyun/spring/ability/PlatformAbilityDispatcher.java +++ b/muyun-ability/src/main/java/net/ximatai/muyun/spring/ability/PlatformAbilityDispatcher.java @@ -310,6 +310,10 @@ private static void runReferenceLoadAfterSelect(CrudA referenceLoadResolver.populate(ability, entity); } + static void populateReferenceLoads(CrudAbility ability, java.util.Collection entities) { + referenceLoadResolver.populateAll(ability, entities); + } + @SuppressWarnings({"rawtypes", "unchecked"}) private static void runReferenceIntegrityValidation(CrudAbility ability, T existing, diff --git a/muyun-ability/src/main/java/net/ximatai/muyun/spring/ability/security/FieldProtectionAbility.java b/muyun-ability/src/main/java/net/ximatai/muyun/spring/ability/security/FieldProtectionAbility.java index bc5e757b..75ce7d7c 100644 --- a/muyun-ability/src/main/java/net/ximatai/muyun/spring/ability/security/FieldProtectionAbility.java +++ b/muyun-ability/src/main/java/net/ximatai/muyun/spring/ability/security/FieldProtectionAbility.java @@ -39,21 +39,26 @@ default PageResult pageQuery(Criteria criteria, PageRequest pageRequest, Sort List records = page.getRecords().stream() .peek(this::restoreProtectedFieldsFromStorage) .toList(); + populateDeclaredReferenceLoads(records); return PageResult.of(records, page.getTotal(), pageRequest); } @Override default List list(Criteria criteria, PageRequest pageRequest, Sort... sorts) { - return getDao().query(activeCriteria(criteria), pageRequest, sorts).stream() + List records = getDao().query(activeCriteria(criteria), pageRequest, sorts).stream() .peek(this::restoreProtectedFieldsFromStorage) .toList(); + populateDeclaredReferenceLoads(records); + return records; } @Override default List list(Criteria criteria, Sort... sorts) { - return getDao().list(activeCriteria(criteria), sorts).stream() + List records = getDao().list(activeCriteria(criteria), sorts).stream() .peek(this::restoreProtectedFieldsFromStorage) .toList(); + populateDeclaredReferenceLoads(records); + return records; } default FieldProtectionMutation protectFieldsForStorage(T entity) { diff --git a/muyun-ability/src/test/java/net/ximatai/muyun/spring/ability/AbilityContractTest.java b/muyun-ability/src/test/java/net/ximatai/muyun/spring/ability/AbilityContractTest.java index 90550314..5bc31581 100644 --- a/muyun-ability/src/test/java/net/ximatai/muyun/spring/ability/AbilityContractTest.java +++ b/muyun-ability/src/test/java/net/ximatai/muyun/spring/ability/AbilityContractTest.java @@ -11,6 +11,7 @@ import net.ximatai.muyun.spring.ability.child.ChildrenAbility; import net.ximatai.muyun.spring.ability.reference.ReferenceDependencyRegistryTestAccess; import net.ximatai.muyun.spring.ability.reference.ReferenceOption; +import net.ximatai.muyun.spring.ability.reference.ReferenceLoadResolver; import net.ximatai.muyun.spring.ability.reference.ReferenceTarget; import net.ximatai.muyun.spring.ability.reference.ReferenceTo; import net.ximatai.muyun.spring.ability.reference.ReferencerAbility; @@ -1848,6 +1849,39 @@ void pageQueryShouldHideSoftDeletedRows() { .containsExactly(activeId, nullDeletedId); } + @Test + void listReadsShouldBatchPopulateReferenceLoadsWithoutLoadingInverseCollections() { + StandardDemoBusinessService service = new StandardDemoBusinessService(); + String firstId = service.insert(new DemoPlainRecord("First")); + String secondId = service.insert(new DemoPlainRecord("Second")); + List> batches = new ArrayList<>(); + PlatformAbilityRuntime.configureReferenceLoadResolver(new ReferenceLoadResolver() { + @Override + public void populate(CrudAbility ability, EntityContract entity) { + throw new AssertionError("list reads must use the batch reference-load entry point"); + } + + @Override + public void populateAll(CrudAbility ability, java.util.Collection entities) { + batches.add(entities.stream().map(EntityContract::getId).toList()); + } + }); + PlatformAbilityRuntime.configureReferencedByResolver((ability, entity) -> { + throw new AssertionError("ordinary list reads must not populate inverse collections"); + }); + + assertThat(service.list(Criteria.of())).extracting(DemoPlainRecord::getId) + .containsExactly(firstId, secondId); + assertThat(service.list(Criteria.of(), PageRequest.of(1, 10))).extracting(DemoPlainRecord::getId) + .containsExactly(firstId, secondId); + assertThat(service.pageQuery(Criteria.of(), PageRequest.of(1, 10)).getRecords()) + .extracting(DemoPlainRecord::getId) + .containsExactly(firstId, secondId); + + assertThat(batches).containsExactly(List.of(firstId, secondId), List.of(firstId, secondId), + List.of(firstId, secondId)); + } + @Test void abilityQueriesShouldNotMutateCallerCriteria() { DemoOrganizationService service = new DemoOrganizationService(); From 8fb16c4e3cd9d4b8f8be96512b4aeee7b090ccab Mon Sep 17 00:00:00 2001 From: Liu Rui Date: Fri, 14 Aug 2026 10:04:43 +0800 Subject: [PATCH 4/4] =?UTF-8?q?refactor:=20=E7=A7=BB=E9=99=A4=E4=B8=9A?= =?UTF-8?q?=E5=8A=A1=E4=BE=A7=E5=BC=95=E7=94=A8=E8=AF=BB=E5=8F=96=E6=8E=A5?= =?UTF-8?q?=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../EmployeeEmploymentReadService.java | 7 +---- .../iam/user/CurrentUserProfileService.java | 7 +---- .../EmployeeEmploymentReadServiceTest.java | 30 +++---------------- .../user/CurrentUserProfileServiceTest.java | 5 +--- 4 files changed, 7 insertions(+), 42 deletions(-) diff --git a/muyun-iam/src/main/java/net/ximatai/muyun/spring/iam/employee/EmployeeEmploymentReadService.java b/muyun-iam/src/main/java/net/ximatai/muyun/spring/iam/employee/EmployeeEmploymentReadService.java index 9031f41b..425ba319 100644 --- a/muyun-iam/src/main/java/net/ximatai/muyun/spring/iam/employee/EmployeeEmploymentReadService.java +++ b/muyun-iam/src/main/java/net/ximatai/muyun/spring/iam/employee/EmployeeEmploymentReadService.java @@ -4,7 +4,6 @@ import net.ximatai.muyun.database.core.orm.PageRequest; import net.ximatai.muyun.database.core.orm.PageResult; import net.ximatai.muyun.database.core.orm.Sort; -import net.ximatai.muyun.spring.ability.reference.ReferenceReadFacade; import net.ximatai.muyun.spring.iam.user.UserAccount; import net.ximatai.muyun.spring.iam.user.UserAccountService; import net.ximatai.muyun.spring.common.model.contract.EntityContract; @@ -23,16 +22,13 @@ public class EmployeeEmploymentReadService { private final EmployeeService employeeService; private final EmployeeAccountService employeeAccountService; private final UserAccountService userAccountService; - private final ReferenceReadFacade referenceReads; public EmployeeEmploymentReadService(EmployeePositionService employeePositionService, EmployeeService employeeService, EmployeeAccountService employeeAccountService, - UserAccountService userAccountService, - ReferenceReadFacade referenceReads) { + UserAccountService userAccountService) { this.employeePositionService = employeePositionService; this.employeeService = employeeService; this.employeeAccountService = employeeAccountService; this.userAccountService = userAccountService; - this.referenceReads = referenceReads; } public PageResult page(Query query) { @@ -61,7 +57,6 @@ private PageResult page(Query query, Map page = employeePositionService.pageQuery(criteria, normalized.pageRequest(), Sort.asc("employeeId")); - referenceReads.enrich(employeePositionService, page.getRecords()); return PageResult.of(views(page.getRecords(), employeeOverrides), page.getTotal(), normalized.pageRequest()); } diff --git a/muyun-iam/src/main/java/net/ximatai/muyun/spring/iam/user/CurrentUserProfileService.java b/muyun-iam/src/main/java/net/ximatai/muyun/spring/iam/user/CurrentUserProfileService.java index 85ffe789..68a5305a 100644 --- a/muyun-iam/src/main/java/net/ximatai/muyun/spring/iam/user/CurrentUserProfileService.java +++ b/muyun-iam/src/main/java/net/ximatai/muyun/spring/iam/user/CurrentUserProfileService.java @@ -3,7 +3,6 @@ import net.ximatai.muyun.database.core.orm.Criteria; import net.ximatai.muyun.database.core.orm.PageRequest; import net.ximatai.muyun.spring.common.identity.CurrentUser; -import net.ximatai.muyun.spring.ability.reference.ReferenceReadFacade; import net.ximatai.muyun.spring.iam.employee.Employee; import net.ximatai.muyun.spring.iam.employee.EmployeeAccountService; import net.ximatai.muyun.spring.iam.employee.EmployeePosition; @@ -20,16 +19,13 @@ public class CurrentUserProfileService { private final EmployeeAccountService employeeAccountService; private final EmployeeService employeeService; private final EmployeePositionService employeePositionService; - private final ReferenceReadFacade referenceReads; public CurrentUserProfileService(EmployeeAccountService employeeAccountService, EmployeeService employeeService, - EmployeePositionService employeePositionService, - ReferenceReadFacade referenceReads) { + EmployeePositionService employeePositionService) { this.employeeAccountService = employeeAccountService; this.employeeService = employeeService; this.employeePositionService = employeePositionService; - this.referenceReads = referenceReads; } public CurrentUserProfile currentProfile(CurrentUser currentUser) { @@ -70,7 +66,6 @@ private CurrentUserProfile.EmployeeProfile employeeProfile(String userId) { private List positions(String employeeId) { List relations = employeePositionService.list( Criteria.of().eq("employeeId", employeeId).eq("enabled", true), new PageRequest(0, 100)); - referenceReads.enrich(employeePositionService, relations); return relations .stream() .map(relation -> new CurrentUserProfile.PositionProfile(relation.getPositionId(), diff --git a/muyun-iam/src/test/java/net/ximatai/muyun/spring/iam/employee/EmployeeEmploymentReadServiceTest.java b/muyun-iam/src/test/java/net/ximatai/muyun/spring/iam/employee/EmployeeEmploymentReadServiceTest.java index 2db3447b..c91630a7 100644 --- a/muyun-iam/src/test/java/net/ximatai/muyun/spring/iam/employee/EmployeeEmploymentReadServiceTest.java +++ b/muyun-iam/src/test/java/net/ximatai/muyun/spring/iam/employee/EmployeeEmploymentReadServiceTest.java @@ -2,14 +2,9 @@ import net.ximatai.muyun.database.core.orm.PageRequest; import net.ximatai.muyun.database.core.orm.PageResult; -import net.ximatai.muyun.spring.ability.reference.ReferenceReadFacade; -import net.ximatai.muyun.spring.ability.reference.ReferenceLoadResolver; -import net.ximatai.muyun.spring.common.model.contract.EntityContract; import net.ximatai.muyun.spring.iam.user.UserAccountService; import org.junit.jupiter.api.Test; -import java.util.ArrayList; -import java.util.Collection; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; @@ -33,30 +28,14 @@ void shouldKeepRetainedEmployeeFieldsInRecycleBinEmploymentProjection() { employment.setId("employment-1"); employment.setEmployeeId("employee-1"); employment.setOrganizationId("org-1"); + employment.setOrganizationTitle("机构一"); employment.setDepartmentId("dept-1"); + employment.setDepartmentTitle("部门一"); employment.setPositionId("position-1"); + employment.setPositionTitle("岗位一"); PageRequest page = PageRequest.of(1, 20); - List> enrichedBatches = new ArrayList<>(); - ReferenceReadFacade referenceReads = new ReferenceReadFacade(new ReferenceLoadResolver() { - @Override - public void populate(net.ximatai.muyun.spring.ability.CrudAbility ability, EntityContract entity) { - throw new AssertionError("employment read must use batch enrichment"); - } - - @Override - public void populateAll(net.ximatai.muyun.spring.ability.CrudAbility ability, - Collection entities) { - enrichedBatches.add(List.copyOf(entities)); - entities.forEach(entity -> { - EmployeePosition relation = (EmployeePosition) entity; - relation.setOrganizationTitle("机构一"); - relation.setDepartmentTitle("部门一"); - relation.setPositionTitle("岗位一"); - }); - } - }); EmployeeEmploymentReadService readService = new EmployeeEmploymentReadService( - employeePositionService, employeeService, employeeAccountService, userAccountService, referenceReads); + employeePositionService, employeeService, employeeAccountService, userAccountService); when(employeePositionService.pageQuery(any(), any(), any())) .thenReturn(PageResult.of(List.of(employment), 1, page)); @@ -74,6 +53,5 @@ public void populateAll(net.ximatai.muyun.spring.ability.CrudAbility ability, assertThat(view.departmentTitle()).isEqualTo("部门一"); assertThat(view.positionTitle()).isEqualTo("岗位一"); }); - assertThat(enrichedBatches).containsExactly(List.of(employment)); } } diff --git a/muyun-iam/src/test/java/net/ximatai/muyun/spring/iam/user/CurrentUserProfileServiceTest.java b/muyun-iam/src/test/java/net/ximatai/muyun/spring/iam/user/CurrentUserProfileServiceTest.java index e1b3e517..623ea453 100644 --- a/muyun-iam/src/test/java/net/ximatai/muyun/spring/iam/user/CurrentUserProfileServiceTest.java +++ b/muyun-iam/src/test/java/net/ximatai/muyun/spring/iam/user/CurrentUserProfileServiceTest.java @@ -3,8 +3,6 @@ import net.ximatai.muyun.database.core.orm.Criteria; import net.ximatai.muyun.database.core.orm.PageRequest; import net.ximatai.muyun.spring.common.identity.CurrentUser; -import net.ximatai.muyun.spring.ability.reference.ReferenceLoadResolver; -import net.ximatai.muyun.spring.ability.reference.ReferenceReadFacade; import net.ximatai.muyun.spring.iam.employee.Employee; import net.ximatai.muyun.spring.iam.employee.EmployeeAccountService; import net.ximatai.muyun.spring.iam.employee.EmployeePositionService; @@ -28,8 +26,7 @@ void shouldPersistOwnContactAndAvatarThroughTheSelfManagedProfileFacade() { when(accountService.employeeIdOfUser("user-1")).thenReturn("employee-1"); when(employeeService.select("employee-1")).thenReturn(employee); when(positionService.list(any(Criteria.class), any(PageRequest.class))).thenReturn(java.util.List.of()); - CurrentUserProfileService service = new CurrentUserProfileService(accountService, employeeService, positionService, - new ReferenceReadFacade(ReferenceLoadResolver.NONE)); + CurrentUserProfileService service = new CurrentUserProfileService(accountService, employeeService, positionService); CurrentUserProfile profile = service.updateCurrentProfile( CurrentUser.tenantUser("user-1", "demo.user", "tenant-a"),