AXForum  
Вернуться   AXForum > Microsoft Dynamics AX > DAX: Прочие вопросы
All
Забыли пароль?
Зарегистрироваться Правила Справка Пользователи Сообщения за день Поиск

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 05.02.2009, 12:23   #1  
kashperuk is offline
kashperuk
Участник
Аватар для kashperuk
MCBMSS
Соотечественники
Сотрудники Microsoft Dynamics
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии 2011
Лучший по профессии 2009
 
4,361 / 2084 (78) +++++++++
Регистрация: 30.05.2004
Адрес: Atlanta, GA, USA
Итак, по-порядку:
Про запрос - спасибо. Это, думаю, достаточное подтверждение того, что второй будет быстрее.

Про 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);
Так вот, после выполнения запроса, единственным заполненным полем вроде должно быть только LineAmount (в текущей имплементации - еще ItemId и EndDisc). При этом, в конструктор класса передаются еще и несколько других полей.
Врядли я настолько плохо понимаю работу с Maps..
Если бы там хотя бы использовались this.поля... А так - поля именно этой переменной
Старый 05.02.2009, 14:13   #2  
ZVV is offline
ZVV
MCITP
MCP
Oracle
MCBMSS
 
1,006 / 246 (11) ++++++
Регистрация: 13.02.2004
Адрес: Минск
->
А, теперь я понял о чём вы...
Вы правы. Но проблемы в этом нет никакой..
Если посмотреть метод расчёта общей скидки (PriceDisc.findEndDisc), вызываемый делее, то там видно, что все эти параметры (priceDiscLine.ItemId, priceDiscLine.inventDim(), priceDiscLine.Unit, priceDiscLine.Qty) там не используются в поиске. А передаются они в унифицированный метод-конструктор просто как пустые значения, можно было и просто явно "нули" прописать, ничего не изменилось бы.
А так может даже и нагляднее чуток получается...

По поводу необходимости условия на заданность номенклатуры - тоже ваша правда. Можно и не задавать. План запросов это никак не меняет всё равно, проверил. Хотя лично я бы оставил - предпочитаю всегда оставлять такие условия, которые подразумеваются по смыслу, хоть они и являются вырожденными в текущей ситуации. Но ситуация может поменяться. И к тому же бывают случаи, когда подобные подсказки оптимизатору могут и помочь, особенно в оракле. А помешают - вряд ли (хотя конечно в жизни всякое бывает )...
__________________
Zhirenkov Vitaly
Старый 05.02.2009, 18:35   #3  
ZVV is offline
ZVV
MCITP
MCP
Oracle
MCBMSS
 
1,006 / 246 (11) ++++++
Регистрация: 13.02.2004
Адрес: Минск
->
Цитата:
Сообщение от kashperuk Посмотреть сообщение
Итак, по-порядку:
Про запрос - спасибо. Это, думаю, достаточное подтверждение того, что второй будет быстрее.
Забыл сразу написать, из головы выпало...

Ещё одним доводом в пользу скорости второго варианта может быть то, что в исходном варианте приходится ещё бежать по курсору и перегонять данные на клиента. Во втором - передаётся только одна, уже посчитанная, сумма.
Так что даже если на сервере запросы выполнятся примерно за сопоставимое время - передача данных по сети может эту разницу увеличить (прямо пропорционально размеру заказа).
(О том насколько большим может быть это влияние я как раз недавно вскользь упоминал вот тут)
__________________
Zhirenkov Vitaly
Старый 05.02.2009, 19:26   #4  
ZVV is offline
ZVV
MCITP
MCP
Oracle
MCBMSS
 
1,006 / 246 (11) ++++++
Регистрация: 13.02.2004
Адрес: Минск
->
Поехали дальше....

2 на мой взгляд бага на 4-ке сп2 с нашей локализацией (восточная европа), слои GLS & GLP.
(На 2009 локализации пока не видел, так что не знаю как там... Может ещё не поздно предупредить )

Таблицы PurchLine & SalesLine.

Для начала метод PurchLine.delete()
(та же картина, только вид сбоку, наблюдается и в SalesLine.insert() и в SalesLine.update() - но там касается только братьев-поляков )
X++:
public void  delete(boolean _showInfoDelReserv = true, boolean deletePBA = true)
{
    PurchLineType purchLineType;
    ;

    purchLineType = this.type();
    purchLineType.delete(_showInfoDelReserv, deletePBA);

    TaxWorkRegulation::deleteRegulation_W(this);
}
В purchLineType.delete() одна транзакция, в TaxWorkRegulation::deleteRegulation_W() - другая. А как же понятие атомарности действия? Одна транзакция прошла, вторая свалилась, ну и ладно? Нехорошо, как-то...

Теперь перейдём к методу SalesLine.delete():
X++:
void delete(Common childBuffer = null, boolean deletePBA = true)
{
    SalesLineType  salesLineType;
    ;

    ttsbegin;

    if (this.AssetId_RU && this.SalesStatus != SalesStatus::Invoiced && ! this.creditNoteLine())
    {
        RAssetTable::updateStatus(this.AssetId_RU, RAssetStatus::Open);
        RAssetTable::updateCustInfo(this.AssetId_RU, '', '');
    }

    salesLineType = this.type();
    salesLineType.delete(childBuffer, deletePBA);

    TaxWorkRegulation::deleteRegulation_W(this);

    ttscommit;
}
Оппачки, тут уже внесли всё в одну транзакцию! Казалось бы, круто, молодцы! НО! Что мы видим в salesLineType.delete()?
Видим внутреннюю транзакцию и перехват ошибок типа Deadlock, UpdateConflict и т.п.
И что происходит из-за появления "внешней" транзакции на SalesLine.delete()?
Правильно, весь эти тщательно пИсаный старшими товарищами код по перехвату ошибок дружно встаёт и уходит сами знаете куда...
Нехорошо, как-то...

Я всё-таки в подобных случаях предпочитаю вносить все свои доработки в единую транзакцию в класс Sales/PurchSalesLine. И, на мой взгляд, так должны были поступить и "локализаторы"...
Или я пропустил какую-то глубокую мысль, которую всё это преследовало?
__________________
Zhirenkov Vitaly
Старый 05.02.2009, 22:02   #5  
Jabberwocky is offline
Jabberwocky
Microsoft Dynamics
Аватар для Jabberwocky
Сотрудники Microsoft Dynamics
 
274 / 307 (11) ++++++
Регистрация: 02.09.2005
Адрес: Москва
Уважаемый ZVV, Вы правы лишь отчасти, и то - с точностью до наоборот. Попробуйте в методе PurchLine.delete() заменить
X++:
TaxWorkRegulation::deleteRegulation_W(this);
на что-нибудь вроде:
X++:
ttsbegin;
throw error('');
ttscommit;
Уверяю Вас, удалить строку закупки Вам после этого не удастся, т.к. при удалении строки из формы неявно (implicit) инициируется транзакция, и возникновение исключения внутри неё или в любой из вложенных транзакций откатывает её (и все вложенные транзакции) полностью.

Отсюда Ваш вывод относительно кода в SalesLine.delete(); также неверен, - здесь как раз транзакционные скобки являются лишними, но их присутствие не так уж критично.
__________________
You should use Bing before asking dumb questions.

Последний раз редактировалось Jabberwocky; 05.02.2009 в 22:10.
За это сообщение автора поблагодарили: ZVV (1).
Старый 05.02.2009, 23:58   #6  
ZVV is offline
ZVV
MCITP
MCP
Oracle
MCBMSS
 
1,006 / 246 (11) ++++++
Регистрация: 13.02.2004
Адрес: Минск
->
Вы чертовски правы, Jabberwocky. Действительно, всё наоборот. Слона то я (неявного) и не приметил. Спасибо!

Даже если вызовы идут и не из формы, а в коде, то там всё равно практически всегда будет присутствовать явная транзакция извне... Разве что вставку можно без транзакции сделать, и тогда всё-таки SalesLine.insert() пройдёт в двух транзакциях. Но это не сильно типичная ситуация, имхо.

Тогда сформулирую обратный вопрос: а зачем в методах Sales/PurchSalesLine.insert/update/delete() организованы эти масштабные try-catch блоки? Ведь получается они никогда не работают, или всё таки работают, но тогда что-то не понимаю когда?
__________________
Zhirenkov Vitaly
Старый 16.02.2009, 19:35   #7  
alex55 is offline
alex55
MCTS
MCBMSS
 
224 / 145 (5) +++++
Регистрация: 13.02.2007
Адрес: Москва
Цитата:
Сообщение от ZVV Посмотреть сообщение
Тогда сформулирую обратный вопрос: а зачем в методах Sales/PurchSalesLine.insert/update/delete() организованы эти масштабные try-catch блоки? Ведь получается они никогда не работают, или всё таки работают, но тогда что-то не понимаю когда?
Работают в случае Exception::UpdateConflict, как минимум:
TTS и try..catch
Старый 17.02.2009, 11:06   #8  
ZVV is offline
ZVV
MCITP
MCP
Oracle
MCBMSS
 
1,006 / 246 (11) ++++++
Регистрация: 13.02.2004
Адрес: Минск
->
Цитата:
Сообщение от alex55 Посмотреть сообщение
Работают в случае Exception::UpdateConflict, как минимум:
TTS и try..catch
Ну да, перехватит, конечно...
И отправит дальше!
Потому что appl.ttsLevel() <> 0...
__________________
Zhirenkov Vitaly
Старый 12.02.2009, 17:35   #9  
ZVV is offline
ZVV
MCITP
MCP
Oracle
MCBMSS
 
1,006 / 246 (11) ++++++
Регистрация: 13.02.2004
Адрес: Минск
->
Небольшой "бажок" на 4.0сп2 (в 2009 этот функционал регистрации отгрузочных накладных переделали, и там этой таблицы уже нет). Но может кому пригодится...

Таблица InventPickingListJournalLine, метод splitByInventTrans

В последнем delete_from явно забыли поле поменять после "копи-пасте"
Вместо
X++:
                inventPickingListJournalLine.InventTransChildType   == this.InventTransChildType    &&
                inventPickingListJournalLine.InventTransChildType   == this.InventTransChildType    &&
должно неверное таки быть:
X++:
                inventPickingListJournalLine.InventTransChildType   == this.InventTransChildType    &&
                inventPickingListJournalLine.InventTransChildRefId   == this.InventTransChildRefId   && // ZVV, Bug fix
__________________
Zhirenkov Vitaly
Старый 17.02.2009, 16:05   #10  
ZVV is offline
ZVV
MCITP
MCP
Oracle
MCBMSS
 
1,006 / 246 (11) ++++++
Регистрация: 13.02.2004
Адрес: Минск
-> Разноска отборочной из отгрузок
dax 2009 sp 1

Создание отборочной из отгрузки...
Имеет место 2 следующих (на мой сугубо личный взгляд - слабо предсказуемых) эффекта (или бага, как кому нравится), оба связаны с ситуацией, когда строка заказа на продажу коплектуется несколькими отгрузками.
Т.е., например, в строке заказа количество 5, из них 2 и 3 обработаны разными отгрузочными и соответсвенно пошли в строки разных отгрузок.

1. При попытке обработать отборочную по двум данным отгрузкам сразу (выделить 2-е на форме отгрузок) обработается только одна из строк отгрузки.
Причина:
класс SalesTotals_ParmTrans
X++:
protected void initRecordSortedListLine()
{
    ;
    recordSortedListLine = new RecordSortedList(tablenum(SalesParmLine));

    recordSortedListLine.sortOrder(fieldnum(SalesParmLine, TableRefId),
                                   fieldnum(SalesParmLine, OrigSalesId),
                                   fieldnum(SalesParmLine, LineNum),
                                   fieldnum(SalesParmLine, SalesLineRecId));
}
Как не сложно догадаться, данный "сортОрдер" является одинаковым для обоих строчек,
в следствие чего при заполнении в этот лист списка строчек, последняя (с кол-вом 3) перезатрёт предыдущую (с кол-вом 2).
Это в классе TradeTotals, метод calc()
X++:
recordSortedListLine.ins(orderLine);
В результате обработается только кол-во из "последней" строки...

Возможные варианты - либо в этом же методе проверять наличие подобной строки в recordSortedListLine и, если есть - суммировать кол-ва (правда в этом случае придётся отдельно проработать вопрос оставшегося кол-ва по строке).
Пробовал на 2009 реализовывать - работает.
Как альтернатива (такое у нас реализовывалось на 3-ке) - переделывать запрос на более ранннем этапе -
в SalesFormLetter_PackingSlip.chooseLinesFromWMSShipmentSet(). По сравнению с той же 3-кой тут кой-чего уже переделали, некоторые баги поправили, но как-то не до конца.
Тут можно переписать, вместо последнего цикла сделать Query по всем имеющимся отгрузкам и изначально просуммировать все нужные кол-ва в одну строку ещё на форме разноска.
Как третий вариант (сам не пробовал, может он и нереализуем) - как-то изменить recordSortedListLine.sortOrder для данного случая.

2. Второй баг более тяжело объяснить... Счас будет много местами бессвязных слов, но кто с этим кодом\функционалом разбирался - надеюсь поймёт.
Теперь разносим только одну отгрузу из двух описанных выше.

Есть метод SalesFormLetter_PackingSlip.resetProformaUponPhysicalUpdatable(), который определяет будет ли реально производится разноска - он работает на основе полей маршрута из WMSOrderTrans и InventTrans.
Т.е. можно разносить, только если ещё остались проводки неразнесённые с таким маршрутом. (иначе будет proforma)
Появляются следующие проблемы:

а) при реальной разноске отборочной эти маршруты никак не учитываются и разнося отборочную по одной отгрузке мы можем разнести проводки по маршруту другой отгрузки.
В итоге чтобы разнести отборочную по второй придётся ещё раз разносить её по первой отгрузке. (извините за каламбур, я предупреждал )
А разнося первую мы как бы разнесли вторую.
И вообще когда таких отгрузок много, можно получить много всяких непредсказуемых эффектов с доступностю птички "разноска" при разноске отборочной по различным отгрузкам.

б) даже если передположить, что проводки будут разноситься по нужным маршрутам, есть ещё проблема, с количеством.
Возвращаемся к примеру с разбитой на 2 отгрузки строкой. 2 и 3.
Предположим мы разносим отгрузку с кол-вом 3, уменьшаем там кол-во до 2-х и разносим.
Остаётся в одной отгрузке 2, в другой - 1. Теперь пытаемся опять разнести ту же отгрузку.
Благодаря методу SalesFormLetter_PackingSlip.createParmLineFromWMSOrderTrans() который проверяет только общее кол-во скомплектованных по строке заказа (без учёта отгрузок и маршрутов), нам опять предложат разнести кол-во 3, и разноска эта пройдёт без проблем, в результате чего разнесётся сразу всё оставшееся кол-во (3).
Т.е. разнося одну отгрузку - мы разнесли обе.
Не знаю, может так, конечно, и задумывалось, но со стороны выглядит как-то уж очень кривенько...

б) решается, вероятно, довольно просто, если SalesFormLetter_PackingSlip.createParmLineFromWMSOrderTrans() проверять не общее кол-во скомплектованных проводок по строке заказа,
X++:
    InventQty       qtyPicked       = _salesLine.pickedInTotalInventUnit();
а только по нужному маршруту.
с а) - кажется сложнее, тут надо параметр какой-то в разноску добавлять, что-ли. Возможно из-за лишнего геморроя на этот момент и решили забить. Не такой уж и частый случай, типа...

PS sorry за многабукаф, короче не получилось...
__________________
Zhirenkov Vitaly
Теги
bug report, баг, ошибка, dynamics

 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
Баги WebTab в DAX4 (более 1-ого на форме) alex55 DAX: Программирование 4 11.07.2008 16:28
Сергей Герасимов: Бизнес-приложения – основа стратегии корпорации Майкрософт Blog bot DAX Blogs 5 27.09.2007 02:00
Сергей Герасимов: О новостных группах и других общедоступных ресурсах Майкрософт Blog bot DAX Blogs 0 09.02.2007 22:52
Сергей Герасимов: Майкрософт ежемесячно публикует список исправленных ошибок Blog bot DAX Blogs 1 16.01.2007 11:52
Счет на оплату по заказу. Баги. Косых Артём DAX: Программирование 2 23.06.2006 11:32

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход

Рейтинг@Mail.ru
Часовой пояс GMT +3, время: 20:51.