13.01.2009, 12:17 | #101 |
Участник
|
DAX 4.0 SP2 - занятный код
Наткнулся недавно на интересный кусок кода на SYS слое в форме COSCalcTrans , отнести это к багам язык не повернулся, скорее можно рассматривать как пример mauvais ton в реализации :
Forms\COSCalcTrans\Data Sources\COSCalcTrans\Methods\executeQuery: X++: public void executeQuery() { ... // date From and To if(dateFrom.dateValue() && dateTo.dateValue()) { qbds.addRange(fieldnum(COSCalcTrans,TransDate)).value(queryValue(dateFrom.dateValue())+"@SYS35672"+"@SYS35672"+queryValue(dateTo.dateValue())); } else { if(dateFrom.dateValue() && ! dateTo.dateValue()) { qbds.addRange(fieldnum(COSCalcTrans,TransDate)).value(queryValue(dateFrom.dateValue())); } } super(); } |
|
|
За это сообщение автора поблагодарили: kashperuk (3). |
15.01.2009, 14:33 | #102 |
Member
|
В ГК в настройках журналов ГК есть опция "Фиксированный корсчет".
Почему эта фича работает только в строках некоторых видах журналов? Например, в общем журнале ГК работает, а в журнале платежей клиентов и поставщиков — нет. И почему контроль доступа к корсчету и его типу реализован на контроле в форме? Если я Морфиксом (настройка формы под пользователя) добавляю на форму пользовательский контрол, то уже могу менять и тип корсчета и сам корсчет даже в общем журнале ГК. Что это вообще за лажа?
__________________
С уважением, glibs® |
|
20.01.2009, 11:41 | #103 |
MCITP
|
Думаю, в случае Оракла эта ситуация могла бы как-то и обрабатываться автоматически.
AX2009 + Oracle + Bug?
__________________
Zhirenkov Vitaly |
|
20.01.2009, 16:12 | #104 |
Member
|
Экзотический модуль Balanced Scorecards
Если открыть Scorecard, выбрать показатель и открыть Objectives, выбрать цель и открыть Target, затем в верхнем гриде ввести несколько строк, выделить две последних и нажать [Alt] + [F9], то система уходит в бесконечный (возможно, очень длинный — не проверял) цикл.
__________________
С уважением, glibs® |
|
21.01.2009, 20:41 | #105 |
Member
|
Это не совсем бага... точнее, бага в голове у этих чертовых новаторов.
В 3.0 при настройке прав доступа когда тычешь в поле (а бывает несколько полей с одинаковой меткой или непонятный перевод), то в левой части формы отображается имя таблицы и поля из АОТ. Тем же, кто знаком с именами полей в АОТ права настраивать было очень удобно по этим подсказкам. В 4.0 и в 5.0 фичу "улучшили". Отображается справка. Смотрится, конечно, красиво, но, как правило, там можно прочитать: "Currently, no information is available for this topic". Было бы лучше, если бы имя таблицы и поля всегда отображалось. Как в 3.0 было.
__________________
С уважением, glibs® |
|
21.01.2009, 21:32 | #106 |
Member
|
4.0 сп2 фп1. Однако, похоже что 5.0 тем же болеет. Вроде в 3.0 еще работало.
В настройке журналов ГК есть поля Active и Approve в группе Approval. Вроде как по документации если поставить галку и указать группу, то журнал не разносится, пока его не одобришь. Сейчас документация очень обтекаемо написана, но раньше одобрить журнал могли только те, кто входил в указанную для него группу одобряющих. Начиная с 4.0 кнопка одобрения доступна всем. Независимо от указанной для журнала группы. Упс... только заметил. Проблемы с кнопкой наблюдаются в форме строк журналов. На заголовке журнала кнопка работает корректно, вроде. Тогда насчет работоспособности в 3.0 я забираю слова назад. Не помню этого нюанса. Что у вас там за диверсант мою любимую главную книжку ломает?
__________________
С уважением, glibs® |
|
28.01.2009, 09:37 | #107 |
Member
|
Наткнулся на кусок кода. if (! this.validate()) throw error(""); Это в АОТ\Classes\CustVendPaymProposalTransferToJournal.run() Не то, чтобы ошибка, но прикольно. Типа "нет слов". Или "потерял дар речи". С другой стороны, по идее, если бы писалось осознано, то должно было бы быть throw Exception::Error;
__________________
С уважением, glibs® |
|
|
За это сообщение автора поблагодарили: kashperuk (5). |
28.01.2009, 10:39 | #108 |
MCITP
|
Это не только в этом методе...
Это вообще много где практикуется... Встречал уже не раз... Тоже считаю, что X++: throw Exception::Error;
__________________
Zhirenkov Vitaly |
|
28.01.2009, 11:33 | #109 |
Member
|
Просто выглядит недописанно. Как будто торопились, не написали, а потом забыли (у самого так бывает иногда). В общем, глаз режет.
А с другой стороны почему бы не написать лишний раз, что не получилось там что-то сделать.
__________________
С уважением, glibs® |
|
28.01.2009, 11:48 | #110 |
MCITP
|
ещё забавный код...
Классы PurchCopying & SalesCopying
метод setRefCustVendCreditInvoicingTable (и в 4 и в 2009) Выглядит типа так... X++: protected void setRefCustVendCreditInvoicingTable(SalesTable _salesTable, CustInvoiceJour _custInvoiceJour) { CustVendCreditInvoicingTable custVendCreditInvoicingTable; ; if(CustParameters::find().CreditInvoicing) { custVendCreditInvoicingTable = CustVendCreditInvoicingTable::findRefId(_salesTable.TableId, _salesTable.RecId, true); if(custVendCreditInvoicingTable) { if(_custInvoiceJour) { custVendCreditInvoicingTable.CustVendCorrectedInvoiceId = _custInvoiceJour.InvoiceId; custVendCreditInvoicingTable.update(); } } else { if(_custInvoiceJour) { custVendCreditInvoicingTable.CustVendInvoiceAccount = _salesTable.InvoiceAccount; custVendCreditInvoicingTable.AccountType = LedgerJournalACType::Cust; custVendCreditInvoicingTable.CustVendCorrectedInvoiceId = _custInvoiceJour.InvoiceId; custVendCreditInvoicingTable.RefTableId = _salesTable.TableId; custVendCreditInvoicingTable.RefRecId = _salesTable.RecId; custVendCreditInvoicingTable.insert(); } } } } Особенно учитывая как в методе Copy() всё это вызывается без всяких проверок...
__________________
Zhirenkov Vitaly |
|
|
За это сообщение автора поблагодарили: kashperuk (5). |
30.01.2009, 16:30 | #111 |
Участник
|
перенес тему в раздел DAX: Прочие вопросы
|
|
04.02.2009, 17:48 | #112 |
MCITP
|
Data Dictionary \ Maps \ PriceDiscHeading \ Methods
X++: server void updateFinalDisc(PriceDiscLine priceDiscLine) { PriceDisc priceDisc; InventTableModule inventTableModule; AmountCur balanceEndDisc; ModuleInventPurchSales moduleType = priceDiscLine.moduleType(); ; while select sum(LineAmount) from priceDiscLine group by ItemId where priceDiscLine.SalesPurchId == this.SalesPurchId && priceDiscLine.ItemId join inventTableModule group by EndDisc where inventTableModule.ItemId == priceDiscLine.ItemId && inventTableModule.ModuleType == moduleType && inventTableModule.EndDisc == NoYes::Yes { balanceEndDisc += priceDiscLine.LineAmount; } ......................................... Явно не для производительности... Разве это не эквивалентно чему-то вроде вот этого: (или я туплю?) X++: select sum(LineAmount) from priceDiscLine where priceDiscLine.SalesPurchId == this.SalesPurchId && priceDiscLine.ItemId join tableId from inventTableModule where inventTableModule.ItemId == priceDiscLine.ItemId && inventTableModule.ModuleType == moduleType && inventTableModule.EndDisc == NoYes::Yes; balanceEndDisc = priceDiscLine.LineAmount;
__________________
Zhirenkov Vitaly |
|
04.02.2009, 19:18 | #113 |
Участник
|
Ну это все же не бага. Результат тот же получится.
Придираетесь |
|
05.02.2009, 00:34 | #114 |
MCITP
|
Вероятно, сначала планировался какой-то более сложный расчёт и от этого остались "рудименты"...
Нет, не баг - опять таки, "забавный код", в какой-то степени подсаживающий производительность... Предлагаете сделать отдельную ветку?
__________________
Zhirenkov Vitaly |
|
05.02.2009, 10:50 | #115 |
Участник
|
Нет, здесь оставьте. Это по сути тоже баг, просто из категории performance.
Вопрос: Виталик, а ты проверил, что второй запрос действительно отрабатывает быстрее? Я понимаю, что "должно". Но проверял ли? И еще - кто-то согласен, что проверка на заполненность ItemId - лишняя? Или думаете специально рассчитано на ситуацию, когда ItemId пустое и в InventTableModule, и в PriceDiscLine...? |
|
05.02.2009, 11:22 | #116 |
Участник
|
И еще вопрос - точнее, скорее таки баг.
У вас тоже переменная priceDiscLine используется в запросе (хотя она передается как параметр), а после использования в запросе передается параметром в класс PriceDisc? |
|
05.02.2009, 12:01 | #117 |
MCITP
|
Цитата:
Но судя по планам испольнения и стоимости запросов - да: Вот примеры обоих запросов на сиквела 2005 (на оракле примерно то же самое) X++: SELECT SUM(A.LINEAMOUNT),A.ITEMID,B.ENDDISC FROM SALESLINE A,INVENTTABLEMODULE B WHERE ((A.DATAAREAID=?) AND ((A.SALESID=?) AND (A.ITEMID>?))) AND ((B.DATAAREAID=?) AND (((B.ITEMID=A.ITEMID) AND (B.MODULETYPE=?)) AND (B.ENDDISC=?))) GROUP BY A.ITEMID,B.ENDDISC ORDER BY A.ITEMID,B.ENDDISC SELECT SUM(A.LINEAMOUNT) FROM SALESLINE A,INVENTTABLEMODULE B WHERE ((A.DATAAREAID=?) AND ((A.SALESID=?) AND (A.ITEMID>?))) AND ((B.DATAAREAID=?) AND (((B.ITEMID=A.ITEMID) AND (B.MODULETYPE=?)) AND (B.ENDDISC=?))) Такая же ситуация и с планами - они практически идентичны, но в первом случае есть ещё sort/aggregate в конце, что существенно увеличивает его стоимость: на сиквеле где-то в 1.5 раза, на оракле в 2. (ну это естественно приблизительные оценки на малых объёмах) По времени на малых объёма различие в доли секунды - второй быстрее. Изменение джоина на exists практически никакого изменения не приносит. Цитата:
Насколько я понимаю по логике общая скидка применяется только к строкам по тем номенклатурам, у которых стоит птичка "общая скидка" в соответсвующем InventTableModule.. Рассчитано наоборот на ситуацию, когда ItemId НЕпустое и в InventTableModule, и в PriceDiscLine... Цитата:
А то что эта переменная-параметр используется в запросе, это вроде как раз нормально - посмотрите как этот метод вызывается в соответсвующих таблицах: f.e. метод на таблице SalesTable: X++: server void updateFinalDisc() { SalesLine salesLine; ; this.PriceDiscHeading::updateFinalDisc(salesLine); //This will trigger the creditlimit calculation when salesTable.validateWrite is called this.Touched = NoYes::Yes; }
__________________
Zhirenkov Vitaly |
|
05.02.2009, 12:23 | #118 |
Участник
|
Итак, по-порядку:
Про запрос - спасибо. Это, думаю, достаточное подтверждение того, что второй будет быстрее. Про priceDiscLine.ItemId - В запросе стоит условие, которое проверяет, что ItemId должно быть НЕ пустое. Но выборка идет, по сути, из двух таблиц. Одна из них, к примеру, SalesLine, и в ней у нас ItemId всегда заполнен, правильно? Вторая - InventTableModule - и там поле ItemId тоже всегда заполнено. (в обоих таблицах есть уникальные индексы, содержащие поле ItemId и еще одно поле) Поэтому получается, что эта проверка - лишняя. Или я чего-то не понял? И напоследок, про саму переменную PriceDiscLine. После запроса, она передается в класс Цитата:
while select sum(LineAmount) from priceDiscLine
group by ItemId where priceDiscLine.SalesPurchId == this.SalesPurchId && priceDiscLine.ItemId join inventTableModule group by EndDisc where inventTableModule.ItemId == priceDiscLine.ItemId && inventTableModule.ModuleType == moduleType && inventTableModule.EndDisc == NoYes::Yes { balanceEndDisc += priceDiscLine.LineAmount; } priceDisc = new PriceDisc(this.moduleType(), priceDiscLine.ItemId, priceDiscLine.inventDim(), priceDiscLine.Unit, priceDate, priceDiscLine.Qty, this.AccountNum, this.Currency); Врядли я настолько плохо понимаю работу с Maps.. Если бы там хотя бы использовались this.поля... А так - поля именно этой переменной |
|
05.02.2009, 14:13 | #119 |
MCITP
|
А, теперь я понял о чём вы...
Вы правы. Но проблемы в этом нет никакой.. Если посмотреть метод расчёта общей скидки (PriceDisc.findEndDisc), вызываемый делее, то там видно, что все эти параметры (priceDiscLine.ItemId, priceDiscLine.inventDim(), priceDiscLine.Unit, priceDiscLine.Qty) там не используются в поиске. А передаются они в унифицированный метод-конструктор просто как пустые значения, можно было и просто явно "нули" прописать, ничего не изменилось бы. А так может даже и нагляднее чуток получается... По поводу необходимости условия на заданность номенклатуры - тоже ваша правда. Можно и не задавать. План запросов это никак не меняет всё равно, проверил. Хотя лично я бы оставил - предпочитаю всегда оставлять такие условия, которые подразумеваются по смыслу, хоть они и являются вырожденными в текущей ситуации. Но ситуация может поменяться. И к тому же бывают случаи, когда подобные подсказки оптимизатору могут и помочь, особенно в оракле. А помешают - вряд ли (хотя конечно в жизни всякое бывает )...
__________________
Zhirenkov Vitaly |
|
05.02.2009, 18:35 | #120 |
MCITP
|
Цитата:
Ещё одним доводом в пользу скорости второго варианта может быть то, что в исходном варианте приходится ещё бежать по курсору и перегонять данные на клиента. Во втором - передаётся только одна, уже посчитанная, сумма. Так что даже если на сервере запросы выполнятся примерно за сопоставимое время - передача данных по сети может эту разницу увеличить (прямо пропорционально размеру заказа). (О том насколько большим может быть это влияние я как раз недавно вскользь упоминал вот тут)
__________________
Zhirenkov Vitaly |
|
Теги |
bug report, баг, ошибка, dynamics |
|
|