|
05.11.2019, 10:05 | #1 |
Участник
|
AX 2009. Дерево, получить всех предков
Есть узел, надо получить список всех узлов, куда он входит.
Есть запрос, который получает родителей по таблицам BOM и BOMTable. PS: bomTable.ItemId_X - это код номенклатуры спецификации X++: while select itemId_X from bomTable join bom where bom.BOMId == bomTable.BOMId && bom.ItemId != bomTable.ItemId_X && bom.ItemId == '01.02.08.01.01.0002' { tmpItemLocal.clear(); tmpItemLocal.ItemId = bomTable.ItemId_X; tmpItemLocal.LineNum = level+1; tmpItemLocal.insert(); } PS: в SQL это будет как-то так: PHP код:
|
|
05.11.2019, 10:34 | #2 |
Участник
|
один сложный запрос не всегда дает наилучшую производительность в многопользовательской системе.
даже в чистом SQL. общая рекомендация для SQL - сводите сложный запрос к нескольким простым, для которых с большой вероятностью есть уже скомпилированные планы в кэше и для которых у SQL есть хорошие эвристики. дополнительная рекомендация для Аксапты - обязательно смотрите на свойство CacheLookup таблицы. в 2009 для таблиц BOM, BOMTable свойство CacheLookup=Found это значит, что простые запросы по этим таблицам возможно вообще не будут отправляться на SQL, аксапта будет возвращать уже найденные записи из кэша. (простые - это запросы по одной таблице, в условиях присутствуют только одно ключевое поле. Как правило, метод find содержит именно такой простой запрос) поэтому вполне возможно, что стоит свести к X++ методу, который оперирует только простыми запросами по таблицам BOM, BOMTable. Тогда в многопользовательской системе, где много разных пользователей работает с BOM, вы с бОльшей вероятностью получите более быстрый код. Главное: * НЕ гонитесь за производительностью ОДНОГО запроса, который выполняется в МОНОПОЛЬНОМ режиме. * постарайтесь поднимать ОБЩУЮ производительность многопользовательской системы |
|
|
За это сообщение автора поблагодарили: SuperStar88 (1). |
05.11.2019, 11:16 | #3 |
Участник
|
Ну, я так понимаю, вопрос ставится так: В каких спецификациях используется указанная номенклатура, с учетом того, что спецификация сама может выступать как номенклатура для других спецификаций
X++: void setLevel(ItemId _itemId, int _level) { BomTable bomTable; Bom bom; ; while select itemId_X from bomTable join bom where bom.BOMId == bomTable.BOMId && bom.ItemId != bomTable.ItemId_X && bom.ItemId == _itemId { tmpItemLocal.clear(); tmpItemLocal.ItemId = bomTable.ItemId_X; tmpItemLocal.LineNum = _level; tmpItemLocal.insert(); // рекурсия setLevel(bomTable.ItemId_X, _level+1); } } ; // Вход в рекурсию setLevel('01.02.08.01.01.0002', 1); Если "зацикливание" возможно, то нужно еще дополнительное поле для записи BomId и дополнительный запрос по tmpItemLocal на предмет существования комбинации BomId+ItemId+LineNum и если такая комбинация есть, то не делать запись и не входить в следующий шаг рекурсии Ну, или просто ограничится глубиной вложенности, скажем, на 10 уровней. Если получилось, что _level больше 10, то это зацикливание и глубже идти не надо. В принципе, можно сделать и цикл по аналогии с SQL. Вполне можно в запрос включить временную таблицу. Но! В Axapta объединение постоянных и временных таблиц в одном запросе зачастую очень плохо кончается. Как минимум, с точки зрения производительности. А в данном случае еще и с пониманием логики выполнения будут проблемы
__________________
- Может, я как-то неправильно живу?! - Отчего же? Правильно. Только зря... |
|
|
За это сообщение автора поблагодарили: mazzy (2), SuperStar88 (1). |
05.11.2019, 11:24 | #4 |
Участник
|
добавлю только что в аксапте уже есть параметр "Макс. уровень спецификации"
|
|
05.11.2019, 13:21 | #5 |
Участник
|
Благодарю, то что надо!
Вот это bom.ItemId != bomTable.ItemId_X должно предотвращать зацикливание, то есть спецификация не может входить сама в себя |
|
05.11.2019, 13:48 | #6 |
Участник
|
Цитата:
Кроме того, просто ItemId проверять не совсем корректно - вполне может быть ситуация, когда номенклатура одна, а конфигурации разные (из одной номенклатуры изготавливаем её подобие, но немного отличающееся) тогда это не зацикливание. Если учесть конфигурационные группы, периоды действия строки спецификации, тип строки спецификации (например, фантомная может разворачиваться) и другие тонкости, то напрямую по таблице пробегать может быть не очень хорошей идеей. В стандартной Аксе есть классы BomSearch* и BOMHierarchy* там можно подсмотреть примеры. |
|
|
За это сообщение автора поблагодарили: mazzy (5). |
06.11.2019, 10:37 | #7 |
Участник
|
Цитата:
Сообщение от Raven Melancholic
Только в самом простом случае - когда вхождение непосредственное. Но оно может быть и на других уровнях в многоуровневой спецификации (то есть, на глубине гораздо большей, чем непосредственное вхождение).
Кроме того, просто ItemId проверять не совсем корректно - вполне может быть ситуация, когда номенклатура одна, а конфигурации разные (из одной номенклатуры изготавливаем её подобие, но немного отличающееся) тогда это не зацикливание. Если учесть конфигурационные группы, периоды действия строки спецификации, тип строки спецификации (например, фантомная может разворачиваться) и другие тонкости, то напрямую по таблице пробегать может быть не очень хорошей идеей. В стандартной Аксе есть классы BomSearch* и BOMHierarchy* там можно подсмотреть примеры. В классах BomSearch* и BOMHierarchy* так и не разобрался. Как с ними правильно работать, есть мануал? |
|
05.11.2019, 13:31 | #8 |
Участник
|
Как вариант, рассмотрите возможность сохранения данных о всех родителях ноды в отдельной таблице.
Т.е. выполнять итерационный пробег или запрос по ветке не в момент когда нужен список всех родителей, а при изменении структуры дерева. Это будет оправдано, если редактирование узлов выполняется реже чем запросы на получение списка родителей.
__________________
Ален ноби, ностра алис. Что означает - если один человек построил, другой завсегда разобрать может. |
|
|
|