05.06.2012, 18:38 | #1 |
Участник
|
Аналог OnValidate в AX
Ищутся рекомендации по применению опыта работы с программным импортом данных в Navision к импорту в Axapta.
В Nav при работе практически с любой таблицей (такой как "Customer" или "Item Journal Line"), можно было смело полагаться на триггеры уровня поля (OnValidate) и уровня таблицы (OnInsert, OnModify) для того чтобы смоделировать кодом поведение пользователя вводящего данные вручную. Код в этих триггерах отвечал как за заполнение зависимых полей в текущей строке, так и за создание необходимых попутных записей в связанных таблицах. Все что нужно было сделать для программного импорта данных это заполнять одно за одним поля и вызывать нужные тригерры в соответствующих местах. Применима ли такая концепция к AX? И если да, то как можно узнать, в каких именно классах и методах хранится код подобный OnValidate, OnInsert и OnModify? Прошу не кидать камнями, если подобные темы уже были; найти не получилось - ткните носом, пожалуйста! |
|
05.06.2012, 20:40 | #2 |
Участник
|
Цитата:
Цитата:
Триггеры insert/update тоже есть, в них может быть прописана логика заполнения/изменения связанных таблиц и проч. Но вот заполнять зависимые поля код в insert/update не должен, по моему глубокому убеждению (ну, максимум какой-нить следующий по счету LineNum подтянуть). Потому что в Аксапте по записи таблицы невозможно понять, было ли значение того или иного поля установлено явно или у него осталось значение по умолчанию (пустое в общем случае), которое можно перезаписать "правильным" значением. Цитата:
Цитата:
На мой взгляд, с точки зрения импорта всякого рода справочников использование этих классов - наиболее прямой путь, но есть, как всегда, нюанс: к сожалению, не для всех таблиц в Аксапте реализованы соотв. AxBC-классы, а если они и есть, то не всегда в них зашита вся необходимая логика. См. также обсуждение В чем преимущество ax-классов перед непосредственной работой с таблицами? |
|
|
За это сообщение автора поблагодарили: S.Kuskov (3), yuh (1). |
05.06.2012, 20:44 | #3 |
Axapta
|
table.validateField(), table.modifiedField(), table.validateWrite(), table.insert() и пр.
Если программист сделал все грамотно и не забыл написать нужный код куда следует и наверняка только в той части, в которой применима к NAV (то есть, думать все равно надо)... Принципиально от NAV отличаться не должно. Есть еще AX* классы, но я сомнвеваюсь, что в кастомизируемом (да и в стандартном) коде эта концепция везде поддерживается и на нее можно полагаться. Не поддерживается. Нельзя. Только надо не забывать, что методы перекрыты бывают не только на уровне таблиц, но и на уровне источников данных форм. А иногда и на конкретных контролах. Так что концепция применима, но так вот просто "Все что нужно было сделать для программного импорта данных это заполнять одно за одним поля и вызывать нужные тригерры в соответствующих местах" сказать нельзя. Не поверю, что в NAV чтобы создать запись в "Item Journal Line" (и других таблицах) всегда достаточно написать так (псевдокод). 'Item Journal Line'.field1 := 1 'Item Journal Line'.onValidateField1() 'Item Journal Line'.field2 := 2 'Item Journal Line'.onValidateField2() 'Item Journal Line'.field3 := 3 'Item Journal Line'.onValidateField3() ... 'Item Journal Line'.OnInsert() 'Item Journal Line'.insert() |
|
|
За это сообщение автора поблагодарили: yuh (1). |
06.06.2012, 13:10 | #4 |
Участник
|
Цитата:
Скажем, мы заполняем журнал для ввода складских остатков. Пример двух зависимых полей - код товара и его стоимость (в простейшем случае, хранится как признак товара в соответствующей записи). Если мы сначала заполним стоимость а потом вернемся и введем код товара, то вполне можно ожидать что система затрет введенное нами значение тем, что записано в справочнике. Но мне кажется что ключ здесь в эмуляции действий пользователя при создании журнала вручную: естественно, что пользователь сначала выбирает товар - и только затем меняет стоимость на требуемую. Значит и наш код должен заполнять поля в том же порядке! Цитата:
В Аксапте есть отлаженный механизм для программного создания и изменения записей таблиц без необходимости заморачиваться дерганием кучи триггеров и, главное, тем, в каком порядке заполнять поля таблиц. Это т.н. AxBC-классы
|
|
06.06.2012, 13:24 | #5 |
Участник
|
Цитата:
Отсюда - другой вопрос: а как это происходит в AX? Нечто подобное? И если да, то какие именно классы используются для создания журналов? |
|
06.06.2012, 13:39 | #6 |
Axapta
|
Цитата:
X++: void createIncomingJournal() { LedgerJournalNameId incomingName; LedgerJournalTable incomingJournal; ledgerJournalTrans incomingTrans; ledgerJournalTrans ledgerJournalTrans; LedgerJournalEngine ljeIn; LedgerJournalEngine ledgerJournalEngine; NumberSeq numSeq; ProjTable projTable; RContractTable rct; RContractPartnerType rctType; ; ttsbegin; select forupdate incomingJournal; incomingJournal.clear(); incomingJournal.initValue(); incomingJournal.JournalName=incomingName; incomingJournal.insert(); ljeIn = new BMLedgerJournalEngine(null); ljeIn.newJournalActive(incomingJournal); if(ljeIn) { while select lines { ledgerJournalTrans=incomingTrans; ledgerJournalEngine=ljeIn; select forupdate ledgerJournalTrans; ledgerJournalTrans.clear(); ledgerJournalTrans.TransDate=lines.PaymDate; ledgerJournalTrans.currencyCode=lines.CurrencyID; ledgerJournalTrans.ExchRate=lines.ExchRate; ledgerJournalTrans.initValue(); ledgerJournalTrans.JournalNum=incomingJournal.JournalNum; ledgerJournalEngine.numberSeqFormHandlerJournal().parmLedgerJournalTrans(ledgerJournalTrans); ledgerJournalEngine.formMethodDataSourceCreatePost(); ledgerJournalEngine.initValue(ledgerJournalTrans); ledgerJournalTrans.TransDate=lines.PaymDate; ledgerJournalTrans.currencyCode=lines.CurrencyID; ledgerJournalTrans.ExchRate=lines.ExchRate; ledgerJournalTrans.accountType=lines.AccountType; ledgerJournalTrans.AccountNum=lines.Account; ledgerJournalTrans.offsetAccountType=lines.offsetAccountType; ledgerJournalTrans.OffsetAccount=lines.offsetAccount; if(AmountDebit) ledgerJournalTrans.AmountCurDebit=lines.AmountDebit; else if(AmountCredit) ledgerJournalTrans.AmountCurCredit=lines.AmountCredit; ledgerJournalTrans.Txt=lines.TransTxt; ledgerJournalTrans.DocumentNum=lines.DocumentNum; ledgerJournalTrans.DocumentDate=lines.PaymDate; ledgerJournalTrans.validateWrite(); ledgerJournalEngine.preWrite(ledgerJournalTrans); ledgerJournalEngine.formMethodDataSourceWritePre(); ledgerJournalTrans.write(); ledgerJournalEngine.write(ledgerJournalTrans); } } ttscommit; if(ljeIn) info(strfmt("Создан журнал входящих платежей %1", incomingJournal.JournalNum)); } Поспрашивал коллег, занимающихся NAV. У них другое мнение. В сферическом идеальном случае да, вызывать табличные триггеры достаточно. Но так это и в AX так. А в реальности бывает и код на формах, который при вызове табличных триггеров, естественно, не сработает. |
|
06.06.2012, 13:40 | #7 |
Axapta
|
Вот пример создания строк складского журнала переноса:
X++: #Define.JournalNum("000015_061") #Define.ItemId("ESB-007") #Define.LocationId("MW") #Define.QtyCounted(101) InventJournalTrans inventJournalTrans; InventJournalTable inventJournalTable; InventTable inventTable; InventDim inventDim; ; inventTable = inventTable::find(#ItemId); if (!inventTable) throw error(strfmt(InventTable::txtNotExist(), #ItemId)); ttsbegin; inventJournalTable = inventJournalTable::find(#JournalNum, true); if (!inventJournalTable) throw error(strfmt(InventJournalTable::txtNotExist(), #JournalNum)); inventJournalTrans.clear(); inventJournalTrans.initFromInventJournalTable(inventJournalTable); inventJournalTrans.initFromInventTable(inventTable); inventJournalTrans.transDate = systemDateGet(); inventDim = inventJournalTrans.inventDim(); inventDim.InventLocationId = #LocationId; inventJournalTrans.inventDimId = InventDim::findOrCreate(inventDim).inventDimId; inventJournalTrans.inventMovement().journalSetInventDimField(inventDim, fieldNum(InventDim, InventLocationId)); inventJournalTrans.Counted = #QtyCounted; inventJournalTrans.inventMovement().JournalSetCounted(); inventJournalTrans.insertFromCode(); ttscommit; |
|
06.06.2012, 13:53 | #8 |
Axapta
|
Ну и еще добавлю, что на одном из проектов разовый импорт в AX мы делали с помощью какой-то программки, которая умела запомнинать действия пользователя на компе и повторять их. Мы ей просто показали для одной строки журнала поячеечный копипаст из Excel в форму AX и эта тулза с удовольствием нагенерила нам нужные строки, пока мы
|
|
|
За это сообщение автора поблагодарили: someOne (3). |
06.06.2012, 13:58 | #9 |
Участник
|
Ну вот, а я бросился было искать мануалы, научающие девелоперов всегда располагать код бизнес-логики в таблицах; при программном создании записей всегда вызывать OnValidate, OnInsert и OnModify;...
По крайней мере, так нас учили раньше и гордо называли это "Navision Way". Может, с выходом более поздних версий что-то поменялось, и теперь этот путь уже не такой прямой |
|
06.06.2012, 14:02 | #10 |
Axapta
|
В AX тоже есть аналог Navision Way - Best Practices:
Цитата:
No code in the forms!
"The purpose of the forms is to support the presentation tier in the three tier client/server model, so you should not find any business logic in the forms." |
|
06.06.2012, 14:16 | #11 |
Участник
|
|
|
06.06.2012, 14:20 | #12 |
Axapta
|
Advanced key and mouse recorder
|
|
06.06.2012, 14:43 | #13 |
Участник
|
Цитата:
Сообщение от yuh
Я думаю, что случай с перезатиранием значений полей страшен только когда мы бессистемно подходим к заполнению записи.
Скажем, мы заполняем журнал для ввода складских остатков. Пример двух зависимых полей - код товара и его стоимость (в простейшем случае, хранится как признак товара в соответствующей записи). Цитата:
Цитата:
В этом плане те же AxBC-классы очень грамотно сделаны: накидал полей, дернул один метод - и подтянулись все возможные связанные поля, не перезатирая те, которые заданы явно, "извне". При этом всегда можно понять, какие поля вообще заданы - извне либо изнутри, за счет логики самого класса. В этом случае действия пользователя по заполнению полей одного за другим - это лишь частный случай общей схемы работы (накидали значений полей - дернули обработчик), только значения полей пользователь всегда накидывает по одному. Последний раз редактировалось gl00mie; 06.06.2012 в 14:46. |
|
|
|