D365FinOp凭证表单关联查询LedgerJournalTrans表数据问询
LedgerTransVoucher表单展示LedgerJournalTrans字段的查询方案
问题背景
需求为在自定义版本的LedgerTransVoucher表单上,展示LedgerJournalTrans表的以下字段:
- PaymMode
- BankChequeNum
- LedgerDimensionName
- JournalNum
前期尝试的各类查询方案均存在问题:要么关联逻辑错误产生笛卡尔积导致记录重复,要么匹配条件不成立导致目标字段返回空值。
现有实现代码
当前代码挂载在表单的GeneralJournalAccountEntry数据源上,通过display方法实现,具体逻辑如下:
public display MH_AccountTitle displayBeneficiaryName(GeneralJournalAccountEntry _accountEntry) { select SubledgerVoucher, AccountingDate from journalEntry where journalEntry.RecId == _accountEntry.GeneralJournalEntry join Voucher, MH_AccountTitle, RecId, AmountCurDebit, AmountCurCredit, TransDate from LedgerTrans where LedgerTrans.Voucher == journalEntry.SubledgerVoucher && LedgerTrans.TransDate == journalEntry.AccountingDate && LedgerTrans.PaymReference == _accountEntry.PaymentReference && (abs(_accountEntry.TransactionCurrencyAmount) == LedgerTrans.AmountCurDebit || abs(_accountEntry.TransactionCurrencyAmount) == LedgerTrans.AmountCurCredit); return ledgerTrans.MH_AccountTitle; }
现有逻辑的明确缺陷
该逻辑为其他方案失效后采用的临时方案,仅能覆盖部分场景,存在两类不可修复的问题:
- 核心关联条件依赖交易日期、凭证号、交易金额这类非唯一字段,当存在多笔同日期、同凭证号、同金额的交易时,会匹配到错误记录
- 强依赖
PaymentReference字段做匹配,当付款方式非支票时,PaymentReference和BankChequeNum字段均为空,关联直接失效
实现约束说明:
- 开发基于自定义改造的
LedgerTransVoucher表单开展,不支持修改系统标准内核逻辑- 选择display方法实现的原因是直接在表单数据源配置表关联无法生效
- 所有自定义代码需挂载在表单的
GeneralJournalAccountEntry数据源上
可行实现方案
关联逻辑说明
直接在表单数据源配置关联无法生效的核心原因是:GeneralJournalAccountEntry与LedgerJournalTrans没有直接的RecId外键映射,属于跨总账、子分类账、日记账模块的链路关联,必须通过系统标准中间表建立匹配关系,禁止使用金额、日期这类业务非唯一字段做关联条件。
标准关联链路为:GeneralJournalAccountEntry→GeneralJournalEntry→SubledgerVoucherGeneralJournalEntry→通过凭证号、会计日期、公司、核算维度匹配LedgerJournalTrans,历史导入无标准子分类账链路的数据,可通过TransactionId做兜底匹配。
参考实现代码
以PaymMode字段的display方法为例,其余字段可复用相同查询逻辑:
[SysClientCacheDataMethodAttribute(true)] // 开启客户端缓存,大幅降低查询开销 public display LedgerJournalPaymMode displayPaymMode(GeneralJournalAccountEntry _accountEntry) { GeneralJournalEntry generalJournalEntry; SubledgerVoucherGeneralJournalEntry subledgerVoucherEntry; LedgerJournalTrans ledgerJournalTrans; // 取关联的总账日记账头记录 generalJournalEntry = GeneralJournalEntry::find(_accountEntry.GeneralJournalEntry); // 优先走标准子分类账凭证链路匹配,准确率100% select firstonly LedgerJournalId, PaymMode, BankChequeNum, LedgerDimension from ledgerJournalTrans exists join subledgerVoucherEntry where subledgerVoucherEntry.GeneralJournalEntry == generalJournalEntry.RecId && subledgerVoucherEntry.Voucher == ledgerJournalTrans.Voucher && subledgerVoucherEntry.AccountingDate == ledgerJournalTrans.TransDate && subledgerVoucherEntry.VoucherDataAreaId == ledgerJournalTrans.DataAreaId && ledgerJournalTrans.LedgerDimension == _accountEntry.LedgerDimension && ledgerJournalTrans.DataAreaId == curext(); // 兜底逻辑:兼容无标准子分类账记录的历史导入数据 if (!ledgerJournalTrans.RecId) { select firstonly LedgerJournalId, PaymMode, BankChequeNum, LedgerDimension from ledgerJournalTrans where ledgerJournalTrans.TransactionId == _accountEntry.TransactionId && ledgerJournalTrans.LedgerDimension == _accountEntry.LedgerDimension && ledgerJournalTrans.DataAreaId == curext(); } return ledgerJournalTrans.PaymMode; }
其余字段实现方式
BankChequeNum、JournalNum:直接复用上述查询逻辑,返回ledgerJournalTrans.BankChequeNum、ledgerJournalTrans.JournalNum即可LedgerDimensionName:拿到ledgerJournalTrans.LedgerDimension后,调用DimensionAttributeValueCombination::getDisplayString(ledgerJournalTrans.LedgerDimension)获取显示名称即可,无需额外关联表
性能优化建议
- 所有display方法必须添加
[SysClientCacheDataMethodAttribute(true)]特性,避免表单滚动时重复触发数据库查询 - 查询语句必须加
firstonly关键字,匹配到第一条符合条件的记录即返回,避免全表扫描 - 如果表单单次加载数据量超过1000行,可在表单数据源的
executeQuery方法后,一次性将当前查询范围内的LedgerJournalTrans记录加载到内存Map中,display方法直接从内存Map取值,加载性能可提升10倍以上
内容的提问来源于stack exchange,提问作者mepemba
相关产品推荐
相关产品推荐

