![]() |
#1 |
Участник
|
![]()
Добрый день.
Собственно тема в заголовке. В руки попал большой проект на 2012-й аксапте. Код изначально похоже был написан еще в ax3.0. Во многих местах для получения остатков запросы идут к InventSum без учета InventSumDelta. В связи с этим вопрос. Если возникнет необходимость, как можно по-быстрому перевести код для учета InventsumDelta без какого либо серьезного переписывания. Первая идея - сделать хитрую вьюху (InventSumView) cо структурой полей аналогичной InventSum, которая делает union InventSum и InventSumDelta (но из InventSumDelta нужно взять актуальные для нас строки, фильтруя их по TTSid). А дальше в коде по мере необходимости заменять запрос к InventSum на InventSumView. Тем самым соблюдается требование на минимальные переделки в коде. Можно в коде в разделе объявления переменных заменять одну строку X++: Inventsum inventsum; X++: InventsumView inventsum; Средствами X++ такую вьюху создать затруднительно. По крайней мере у меня пока нет идей, кроме как подменять ее определение в SQL. Как замена создал Union-Query GRD_InventSumAllQuery (данные во вложении). Там описанная идея реализована. Фильтрация по InventsumDelta.TTSid работает. На SQL уходит примерно такой запрос X++: SELECT T1.ARRIVED,T1.AVAILORDERED,T1.AVAILPHYSICAL,T1.DEDUCTED,T1.INVENTDIMID,T1.ITEMID,T1.LASTUPDDATEEXPECTED,T1.LASTUPDDATEPHYSICAL,T1.ONORDER,T1.ORDERED,T1.PHYSICALINVENT,T1.PHYSICALVALUE,T1.PHYSICALVALUESECCUR_RU,T1.PICKED,T1.POSTEDQTY,T1.POSTEDVALUE,T1.POSTEDVALUESECCUR_RU,T1.QUOTATIONISSUE,T1.QUOTATIONRECEIPT,T1.RECEIVED,T1.REGISTERED,T1.RESERVORDERED,T1.RESERVPHYSICAL,T1.RECID,1 FROM INVENTSUM T1 WHERE ((PARTITION=5637144576) AND (DATAAREAID=N'GRD')) UNION ALL SELECT T1.ARRIVED,T1.AVAILORDERED,T1.AVAILPHYSICAL,T1.DEDUCTED,T1.INVENTDIMID,T1.ITEMID,T1.LASTUPDDATEEXPECTED,T1.LASTUPDDATEPHYSICAL,T1.ONORDER,T1.ORDERED,T1.PHYSICALINVENT,T1.PHYSICALVALUE,T1.PHYSICALVALUESECCUR_RU,T1.PICKED,T1.POSTEDQTY,T1.POSTEDVALUE,T1.POSTEDVALUESECCUR_RU,T1.QUOTATIONISSUE,T1.QUOTATIONRECEIPT,T1.RECEIVED,T1.REGISTERED,T1.RESERVORDERED,T1.RESERVPHYSICAL,T1.RECID,2 FROM INVENTSUMDELTA T1 WHERE (((PARTITION=5637144576) AND (DATAAREAID=N'GRD')) AND ((ISAGGREGATED=0) AND (TTSID=5637758929))) ORDER BY 6 Может есть идея как еще можно сделать ? P.S. Ax2012 R3 CU9 P.P.S. В этой теме Остатки по номенклатуре в разрезе складов внутри транзакции было обсуждение похожей проблемы Предложили хорошие варианты решения, но здесь они не подходят так как придется сильно код переписывать. Последний раз редактировалось Logger; 19.05.2017 в 11:05. |
|
![]() |
#2 |
Участник
|
Цитата:
InventsumDelta "живет" только в рамках транзакции. при завершении транзакции все дельта переносятся в inventSum поэтому дельту стоит учитывать только в рамках той же транзакции, в которой происходит создание-изменение данных. грубо говоря дельту стоит учитывать только для чтения грязных данных. в остальных случаях inventSum вполне достаточно. тебе точно дельта нужна? |
|
![]() |
#3 |
Участник
|
Это я понимаю. Вопрос задан именно для тех случаев когда нужна дельта. Я понимаю что это не всегда надо.
Т.е. вопрос в том, что если потребовалось учесть дельту, то как это сделать максимально простым способом без сильных переписываний и не мучаясь с объединением результатов двух запросов. |
|
![]() |
#4 |
Участник
|
Плюс, если бы можно было создать такую вьюху или если бы с квериком из примера можно было бы обращаться как с вьюхой или табличным мапом, то можно было бы всегда ее в коде использовать.
Так было бы удобнее. Потому что, написал, например, программист какой-нибудь класс, который в процессе работы делает запрос к Inventsum и на основе остатков что-то делает. А затем этот класс захотели использовать в рамках другого более сложного алгоритма в одной транзакции. И тут лезут проблемы. Оказывается что остатки в InventSum неактуальные и все такое. Т.е. код использующий InventSum - не совсем переносимый. Его в другом месте просто так не заюзаешь. А всего-то надо, чтобы ядро позволяло использовать Query как табличный map или View и дело в в шляпе. (Просто создать View на основе Query не прокатывает. Query позволяет динамически фильтры формировать, а View в момент создания их фиксирует) Последний раз редактировалось Logger; 19.05.2017 в 11:38. |
|
![]() |
#5 |
Участник
|
мне кажется, что обсуждение вопроса можно и должно разложить на случаи:
1. сделать быстро 2. сделать хорошо 2.1. сделать хорошо select 2.2. сделать хорошо query для начала хотелось бы убедиться что способ "сделать быстро" не подходит по тем или иным причинам. итак, "сделать быстро": есть группа методов InventSum.addInventSumDelta эти методы работают следующим образом:
да, это далеко не оптимальный с точки зрения производительности способ. но легко программируется и легко читается при поддержке. мне кажется, что этот способ стоит использовать даже в случае 2.1. для 2.2. лучше использовать стандартные методы NewQuery, queryAddSumFields и подобные. главное, не вклиниваться в исходный код, а сделать... хм... extension. |
|
![]() |
#6 |
Moderator
|
Можно посмотреть на sysComputedColumn и примеры его использования.
По большому счету - весь этот механизм генерирует текст с определением вычислимого поля для view. Более того - есть подозрение что при некотором упорстве туда тупо можно засунуть SQL, который эту колонку будет рассчитывать для данного itemId и inventDim. То есть - написать хранимку в сиквеле, а потом в DAX2012 определить view состоящий из inventSum и вычислимого поля. А в самом определении поля засунуть вызов хранимки с текущим значением inventSum.itemId и inventSum.inventDimId. Конечно хранимка будет не очень быстро работать и на большой выборке запрос по подобному view будет работать долго, но для конкретных небольших выборок оно вполне даже может прилично отрабатывать... Можно кстати определить вычислимое поле как inventSum.postedQty+unconfirmedPostedQty(inventSum.itemId, inventSum.inventDimId). Есть правда проблема того как обрабатывать ситуацию с текущей сессией, по которой надо собирать неподтвержденные операции. Я бы попытался сделать картезианское произведение SysClientSessions и InventSum, при этом значение sessionId передавал бы в хранимую процедуру. Также SessionId надо будет вывести как дополнительное поле во view, а в любых запросах писать что-то типа: Select sum(postedQty) from mySuperView where mySuperView.sessionId==sessionId() && mysuperView.itemid==itemId В общем - в зависимости от мощности вашего сервера оно может сработать, а может и не сработать ![]() |
|
|
За это сообщение автора поблагодарили: Logger (3). |
![]() |
#7 |
Участник
|
Цитата:
Сообщение от fed
![]() Можно посмотреть на sysComputedColumn и примеры его использования.
мне кажется, что для грязных данных. это какой-то перебор. |
|
![]() |
#8 |
Участник
|
Основная проблема как мне кажется - научить вьюху отбирать из InventSumDelta записи с нужным TTSid - актуальным для текущей сессии.
Можно в служебную табличку (XXServiceTable ) в начале транзакции (в методе application.ttsNotifyPostBegin писать соответствие ttsId и @@SPID - до конца транзакции ни ttsId ни @@SPID не поменяется. А за пределами транзакции для уже поюзанного номера ttsId выборка из InventSumDelta всегда пустая) Ну а затем во вьюхе добавить условие - фильтровать InventSumDelta.TTsId по значению прописанного в вспомогательной табличке. Его легко достать через подзапрос X++: select ttsId from XXServiceTable where sid = @@SPID По идее это все не должно утяжелить запрос. Данные в InvnetSumDelta игрушечные по сравнению с Inventsum. Она практически всегда пустая. Последний раз редактировалось Logger; 19.05.2017 в 12:09. |
|
![]() |
#9 |
Moderator
|
Можно еще context_info использовать. Указывать контекстную информацию в postTtsBegin() и очишать в preTTSCommit()
|
|
![]() |
#10 |
Участник
|
Да точно.
Я тоже сперва про нее подумал, но потом решил отказаться. У нас в реестре включен флажок (Мониторинг работы), по которому ядро в эту переменную пишет разную служебную инфу. Боюсь пересекутся. Последний раз редактировалось Logger; 19.05.2017 в 12:46. |
|
![]() |
#11 |
Участник
|
Пример с 1-го раза не вложился.
|
|
![]() |
#12 |
Участник
|
Цитата:
Далее, для запросов (без forupdate) в Ax2012 всё ещё используется Read Committed Snapshot Isolation? Если всё это так, то "чужие" записи в ней просто невозможно увидеть, т.е. условие по ttsId, казалось бы, просто не нужно (оно лишь оптимизирует выборку)... |
|
|
За это сообщение автора поблагодарили: Logger (3). |
![]() |
#13 |
Участник
|
На первый взгляд это так, но как-то это ненадежно. Высок риск получить блокировку. Т.е. для поиграться - подойдет, а на продуктиве как-то стремно писать код который закладывается на такие вещи.
|
|
Теги |
ax2012, inventsum, inventsumdelta |
|
Опции темы | Поиск в этой теме |
Опции просмотра | |
|