[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6ACNJGZDF8TE50P0VA9JCYS":3,"skill-same:01M6ACNJGZDF8TE50P0VA9JCYS":46},{"skillNo":4,"name":5,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":17,"publishedAt":19,"linkOnly":20,"markdownContent":21,"markdownBody":21,"frontMatter":22,"refName":23,"commitSha":24,"skillDirectory":25,"forksCount":26,"repositoryHtmlUrl":27,"repositoryHomepageUrl":28,"ownerHtmlUrl":29,"ownerBlogUrl":30,"ownerDescription":6,"updatedAt":31,"install":32,"resources":45},"01M6ACNJGZDF8TE50P0VA9JCYS","manage-dynamic-view-entities",null,"apache\u002Fofbiz-plugins","apache","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F47359?v=4","01M6AC83E6K4FDKK7HZ8WNMQKE","The Apache Software Foundation","01M6ACMJJ1Q4WYATY4GXZ2FAVD",178,"Apache-2.0","https:\u002F\u002Fgithub.com\u002Fapache\u002Fofbiz-plugins\u002Fblob\u002Ftrunk\u002Fai-agent-skills\u002Fmanage-dynamic-view-entities\u002FSKILL.md",[],[18],"manage dynamic view entities","2026-11-10 10:12:30",false,"\u003C!--\nLicensed to the Apache Software Foundation (ASF) under one\nor more contributor license agreements.  See the NOTICE file\ndistributed with this work for additional information\nregarding copyright ownership.  The ASF licenses this file\nto you under the Apache License, Version 2.0 (the\n\"License\"); you may not use this file except in compliance\nwith the License.  You may obtain a copy of the License at\n\nhttp:\u002F\u002Fwww.apache.org\u002Flicenses\u002FLICENSE-2.0\n\nUnless required by applicable law or agreed to in writing,\nsoftware distributed under the License is distributed on an\n\"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\nKIND, either express or implied.  See the License for the\nspecific language governing permissions and limitations\nunder the License.\n-->\n\n---\nname: manage-dynamic-view-entities\ndescription: Programmatically build complex queries using the DynamicViewEntity API for runtime query variability.\n---\n\n# manage-dynamic-view-entities\n\nUse `DynamicViewEntity` when the join structure, selected aliases, or aggregation must be built at runtime. Prefer explicit aliases, add conditions only for aliases that exist in the dynamic view, and use group-by correctly when aggregate functions are present.\n\nProgrammatically build complex queries using the `DynamicViewEntity` API. This is essential when query structures (joins, aliases) depend on runtime parameters that cannot be statically defined in `entitymodel.xml`.\n\n## Triggers\n- Dynamic search screens with optional joins based on user input.\n- Reporting tools that allow selecting arbitrary fields or grouping criteria at runtime.\n- Scenarios requiring \"self-joins\" (aliasing the same entity multiple times).\n- Projections or aggregations that vary based on logic.\n\n## Static vs. Dynamic View Entities\n\n| Feature | Static View Entity (XML) | Dynamic View Entity (Java\u002FGroovy) |\n| :--- | :--- | :--- |\n| **Visibility** | Visible in Webtools; pre-parsed; cached | Scoped to logic; minor runtime overhead |\n| **Flexibility** | Fixed join structure | Conditional joins\u002Faliases based on input |\n| **Reuse** | Highly reusable across services\u002Fscreens | Ad-hoc, used and thrown away |\n| **Preference** | **Primary Choice** for stable\u002Freusable logic | Use only for **actual runtime variability** |\n\n## Best Practices\n- **Resource Scoping**: Keep `DynamicViewEntity` objects within the method scope; they are designed for immediate use.\n- **Explicit Aliases**: Prefer explicit `addAlias` calls over `addAliasAll` when joining multiple entities to avoid field name collisions and over-selection.\n- **Minimal Joins**: Only join tables strictly necessary for the active logic path.\n- **Alias Safety**: Always ensure that `EntityCondition` and `orderBy` clauses reference the **aliases** exposed by the view, not the underlying entity field names.\n\n## Procedure\n\n### 1. Initialize DynamicViewEntity\nInstantiate the container.\n\n### 2. Add Member Entities\nUse unique aliases for each member. You can add the same entity multiple times with different aliases (Self-Join).\n\n### 3. Add Aliases (Projections)\nExplicitly select fields. Use `addAliasAll` only for the base entity when field overlap is not a concern.\n\n### 4. Create View Links (Joins)\nThe `relOptional` (Boolean) argument determines the join type:\n- `Boolean.FALSE`: Inner Join (default behavior).\n- `Boolean.TRUE`: Left Outer Join (preserves parent rows if related row is missing).\n\nUse `ModelKeyMap.makeKeyMapList(\"fieldId\")` as a convenience for standard field-to-field mapping.\n\n### 5. Execute Query\nChoose the correct result set handler:\n- `queryList()`: For small to medium result sets.\n- `queryIterator()`: For large results (streaming). **Must be closed** in a `finally` block or try-with-resources.\n\n## Guardrails\n1. **Alias Safety**: Only reference active aliases in conditions and sorting. Reference by the name exposed in `addAlias`.\n2. **Explicit Aliases**: Always prefer explicit aliases over `addAliasAll` when joining multiple entities.\n3. **Aggregation Grouping**: When using aggregate functions (sum, count, etc.), every non-aggregated field must have `groupBy=\"true\"`.\n4. **Static Preference**: If the query structure is stable and reused, prefer a static `\u003Cview-entity>` in XML.\n5. **Unique Member Aliases**: Use unique aliases for every member entity, especially for self-joins.\n6. **Resource Management**: Always close `EntityListIterator` properly.\n7. **No Caching**: Dynamic views are NOT cached by the entity engine.\n8. **Distinct**: Use `.distinct()` on `EntityQuery` if your join results in duplicates.\n9. **PK Mapping**: Ensure the `ModelKeyMap` accurately reflects the PK\u002FFK relationship.\n\n## Anti-Patterns\n- **❌ Cartesian Products**: Forgetting `addViewLink` between members causes a cross-join.\n- **❌ Infinite Joins**: Adding too many member entities leads to massive, unperformant SQL.\n- **❌ Dead Conditions**: Applying an `EntityCondition` on an alias that was not added to the `DynamicViewEntity`.\n- **❌ Field Overwrites**: Using the same alias name for different fields without unique `name` parameters.\n\n## Examples\n\n### Positive Patterns (Good)\n\n#### 1. Standard Join with Alias Safety and Distinct\nCovers: Procedure 1-5, Guardrails 1, 2, 8, 9.\n```java\nDynamicViewEntity dve = new DynamicViewEntity();\ndve.addMemberEntity(\"OH\", \"OrderHeader\");\ndve.addMemberEntity(\"OT\", \"OrderType\");\n\n\u002F\u002F Join using convenience method and proper PK\u002FFK mapping\ndve.addViewLink(\"OH\", \"OT\", Boolean.FALSE, ModelKeyMap.makeKeyMapList(\"orderTypeId\"));\n\n\u002F\u002F Explicit aliases to avoid over-selection\ndve.addAlias(\"OH\", \"orderId\", \"id\", null, null, null, null);\ndve.addAlias(\"OT\", \"description\", \"orderTypeDesc\", null, null, null, null);\n\n\u002F\u002F Condition references exposed ALIAS \"id\", not \"orderId\"\nEntityCondition cond = EntityCondition.makeCondition(\"id\", \"10000\");\n\nList\u003CGenericValue> list = EntityQuery.use(delegator)\n    .from(dve)\n    .where(cond)\n    .distinct(true) \n    .queryList();\n```\n\n#### 2. Conditional Query with Optional Joins\nCovers: Guardrail 1 (logic safety) and Procedure 4 (`relOptional`).\n```java\nif (UtilValidate.isNotEmpty(partyId)) {\n    \u002F\u002F Left Outer Join: Boolean.TRUE\n    dve.addMemberEntity(\"BILL_TO\", \"OrderRole\");\n    dve.addViewLink(\"OH\", \"BILL_TO\", Boolean.TRUE, ModelKeyMap.makeKeyMapList(\"orderId\"));\n    dve.addAlias(\"BILL_TO\", \"partyId\", \"billToPartyId\", null, null, null, null);\n}\n\nList\u003CEntityCondition> conds = new ArrayList\u003C>();\n\u002F\u002F Best Practice: Only apply condition if the alias was actually added to the DVE\nif (dve.getMemberModelMemberEntities().containsKey(\"BILL_TO\")) {\n    conds.add(EntityCondition.makeCondition(\"billToPartyId\", partyId));\n    conds.add(EntityCondition.makeCondition(\"roleTypeId\", \"BILL_TO_CUSTOMER\"));\n}\n```\n\n#### 3. Self-Join (Multiple Aliases for Same Entity)\nCovers: Guardrail 5 and Procedure 2.\n```java\n\u002F\u002F Join OrderRole twice for different purposes\ndve.addMemberEntity(\"SHIP_TO_ROLE\", \"OrderRole\");\ndve.addMemberEntity(\"BILL_TO_ROLE\", \"OrderRole\");\n\ndve.addViewLink(\"OH\", \"SHIP_TO_ROLE\", Boolean.FALSE, ModelKeyMap.makeKeyMapList(\"orderId\"));\ndve.addViewLink(\"OH\", \"BILL_TO_ROLE\", Boolean.FALSE, ModelKeyMap.makeKeyMapList(\"orderId\"));\n\ndve.addAlias(\"SHIP_TO_ROLE\", \"partyId\", \"shipToPartyId\", null, null, null, null);\ndve.addAlias(\"BILL_TO_ROLE\", \"partyId\", \"billToPartyId\", null, null, null, null);\n```\n\n#### 4. Aggregation and Grouping\nCovers: Guardrail 3.\n```java\nDynamicViewEntity dve = new DynamicViewEntity();\ndve.addMemberEntity(\"OI\", \"OrderItem\");\n\n\u002F\u002F Every non-aggregated field MUST have groupBy=true\ndve.addAlias(\"OI\", \"productId\", \"productId\", null, null, Boolean.TRUE, null);\ndve.addAlias(\"OI\", \"quantity\", \"totalQuantity\", null, null, null, \"sum\");\n\nList\u003CGenericValue> summary = EntityQuery.use(delegator).from(dve).queryList();\n```\n\n#### 5. Complex Expressions (ComplexAlias)\n```java\nimport org.apache.ofbiz.entity.model.ModelViewEntity.ComplexAlias;\nimport org.apache.ofbiz.entity.model.ModelViewEntity.ComplexAliasField;\n\nComplexAlias lineTotal = new ComplexAlias(\"*\");\nlineTotal.addComplexAliasMember(new ComplexAliasField(\"OI\", \"unitPrice\", null, null));\nlineTotal.addComplexAliasMember(new ComplexAliasField(\"OI\", \"quantity\", null, null));\ndve.addAlias(null, \"lineTotal\", null, null, null, null, null, lineTotal);\n```\n\n#### 6. Resource Management (Iterator)\nCovers: Guardrail 6 and Procedure 5.\n```java\ntry (EntityListIterator eli = EntityQuery.use(delegator).from(dve).queryIterator()) {\n    GenericValue value;\n    while ((value = eli.next()) != null) {\n        \u002F\u002F process streaming results\n    }\n}\n```\n\n### Negative Patterns (Bad)\n\n#### ❌ Cartesian Product (Missing Join)\n```java\ndve.addMemberEntity(\"OH\", \"OrderHeader\");\ndve.addMemberEntity(\"OI\", \"OrderItem\");\n\u002F\u002F BUG: Missing addViewLink(\"OH\", \"OI\", ...) causes DB crash on large tables\n```\n\n#### ❌ Dead Condition (Missing Member)\n```java\n\u002F\u002F CRASH PROBABLE: \"productId\" alias doesn't exist if someFlag is false\nif (someFlag) {\n    dve.addMemberEntity(\"OI\", \"OrderItem\");\n    dve.addAlias(\"OI\", \"productId\");\n}\nEntityCondition cond = EntityCondition.makeCondition(\"productId\", \"foo\"); \nList\u003CGenericValue> list = EntityQuery.use(delegator).from(dve).where(cond).queryList();\n```\n\n#### ❌ Infinite Joins (Over-Joining)\n```java\n\u002F\u002F BUG: Joining too many entities (e.g., 10+) leads to timeouts\ndve.addMemberEntity(\"E1\", \"Table1\");\n\u002F\u002F ... add 9 more member entities ...\ndve.addMemberEntity(\"E10\", \"Table10\");\n\u002F\u002F RECOMMENDATION: Materialize as Database View or break into multiple queries\n```\n\n#### ❌ Field Overwrite (Duplicate Alias)\n```java\ndve.addAlias(\"OH\", \"statusId\");\ndve.addAlias(\"OT\", \"statusId\"); \u002F\u002F Overwrites OH.statusId; OH value becomes inaccessible\n```\n",{},"trunk","6c6c27710443de03e9247605d33a2e2f5bc3d1e2","ai-agent-skills\u002Fmanage-dynamic-view-entities",222,"https:\u002F\u002Fgithub.com\u002Fapache\u002Fofbiz-plugins","https:\u002F\u002Fofbiz.apache.org\u002F","https:\u002F\u002Fgithub.com\u002Fapache","https:\u002F\u002Fwww.apache.org\u002F","2026-11-12 22:04:06",{"source":7,"skillName":5,"commands":33,"prompt":43,"zipAvailable":44},[34,37,40],{"tool":35,"command":36},"npx","npx skills add apache\u002Fofbiz-plugins --skill manage-dynamic-view-entities",{"tool":38,"command":39},"bunx","bunx skills add apache\u002Fofbiz-plugins --skill manage-dynamic-view-entities",{"tool":41,"command":42},"pnpm","pnpm dlx skills add apache\u002Fofbiz-plugins --skill manage-dynamic-view-entities","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fapache\u002Fofbiz-plugins\u002Fblob\u002Ftrunk\u002Fai-agent-skills\u002Fmanage-dynamic-view-entities\u002FSKILL.md",true,[],[47,54,61,68,75,82],{"skillNo":48,"name":49,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":50,"categories":51,"keywords":52,"publishedAt":19},"01M6ACQSN90YKJZ92MQ52D9R8H","prepush-readiness","https:\u002F\u002Fgithub.com\u002Fapache\u002Fofbiz-plugins\u002Fblob\u002Ftrunk\u002Fai-agent-skills\u002Fprepush-readiness\u002FSKILL.md",[],[53],"prepush readiness",{"skillNo":55,"name":56,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":57,"categories":58,"keywords":59,"publishedAt":19},"01M6ACQPR1WRA751V4DXVC3AHF","manage-webapps","https:\u002F\u002Fgithub.com\u002Fapache\u002Fofbiz-plugins\u002Fblob\u002Ftrunk\u002Fai-agent-skills\u002Fmanage-webapps\u002FSKILL.md",[],[60],"manage webapps",{"skillNo":62,"name":63,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":64,"categories":65,"keywords":66,"publishedAt":19},"01M6ACQMCX8Z7NY2CE08NCV6ND","manage-themes","https:\u002F\u002Fgithub.com\u002Fapache\u002Fofbiz-plugins\u002Fblob\u002Ftrunk\u002Fai-agent-skills\u002Fmanage-themes\u002FSKILL.md",[],[67],"manage themes",{"skillNo":69,"name":70,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":71,"categories":72,"keywords":73,"publishedAt":19},"01M6ACQHYN20AFWF6TKK4RGQ8A","manage-tests","https:\u002F\u002Fgithub.com\u002Fapache\u002Fofbiz-plugins\u002Fblob\u002Ftrunk\u002Fai-agent-skills\u002Fmanage-tests\u002FSKILL.md",[],[74],"manage tests",{"skillNo":76,"name":77,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":78,"categories":79,"keywords":80,"publishedAt":19},"01M6ACQFRMW7R45YD3HRAXPGWF","manage-templates","https:\u002F\u002Fgithub.com\u002Fapache\u002Fofbiz-plugins\u002Fblob\u002Ftrunk\u002Fai-agent-skills\u002Fmanage-templates\u002FSKILL.md",[],[81],"manage templates",{"skillNo":83,"name":84,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":85,"categories":86,"keywords":87,"publishedAt":19},"01M6ACQCSSDZQMD8VX2K3WRR93","manage-strategies","https:\u002F\u002Fgithub.com\u002Fapache\u002Fofbiz-plugins\u002Fblob\u002Ftrunk\u002Fai-agent-skills\u002Fmanage-strategies\u002FSKILL.md",[],[88],"manage strategies"]