![]() |
#1 |
Участник
|
Preston.Larimer: Dynamic selection criteria in X++
Источник: http://palarimer.greenlight2go.com/2...eria-in-x.html
============== Occasionally I’ve had a situation where using a while select statement to loop through a set of records and needed the fields used in the selection criteria to be dynamic based on arguments passed to the method. Dynamics AX offers a slick way of dealing with this that is used in the standard application code but is still pretty obscure. The following method demonstrates using a variable select statement based on passed in arguments and using the NEXT keyword to move the record set forward. In this example we’re just outputting the Item ID to an info log but you could get much more creative…. X++: void SelectNextSample(salesID _salesID, inventtransID _inventTransID = '') { salesLine salesLine; ; if (_inventTransID) { select salesLine where salesLine.SalesId == _salesID && salesLine.InventTransId == _inventTransID; } else { select salesLine where salesLine.SalesId == _salesID; } while (salesLine) { info(salesLine.ItemId); next salesLine; } } Источник: http://palarimer.greenlight2go.com/2...eria-in-x.html
__________________
Расскажите о новых и интересных блогах по Microsoft Dynamics, напишите личное сообщение администратору. |
|
![]() |
#2 |
Administrator
|
Пример неудачный. В этом случае (с if) лучше Query воспользоваться. Но формально - такой код работать будет
__________________
Возможно сделать все. Вопрос времени |
|
|
За это сообщение автора поблагодарили: mazzy (2). |
![]() |
#3 |
Ищущий знания...
|
эээ, а почему не сделать проще? вот так например:
X++: void SelectNextSample(salesID _salesID, inventtransID _inventTransID = '') { salesLine salesLine; ; while select salesLine where salesLine.SalesId == _salesID && (salesLine.InventTransId == _inventTransID || _inventTransID == '') { info(salesLine.ItemId); } } ![]()
__________________
"Страх перед возможностью ошибки не должен отвращать нас от поисков истины." (с) С Уважением, Елизаров Артем |
|
![]() |
#4 |
Administrator
|
2lev: Я ж говорю - пример неудачный. Возможно, автор в своем примере хотел показать - что если саму выборку конструировать отдельно от цикла пробега - то есть оператор next. В случае с Query это бывает актуально - когда один метод конструирует запрос, а второй - бегает по циклу.
Эх... жаль, если такие люди пишут sys-слой АХ...
__________________
Возможно сделать все. Вопрос времени |
|
![]() |
#5 |
Участник
|
Вспомнил сейчас только один случай из своей практики, когда мне действительно понадобилось вручную управлять движением курсоров. Задача требовала независимого движения двух курсоров по одной выборке.
|
|
![]() |
#6 |
Ищущий знания...
|
Цитата:
Сообщение от sukhanchik
![]() 2lev: Я ж говорю - пример неудачный. Возможно, автор в своем примере хотел показать - что если саму выборку конструировать отдельно от цикла пробега - то есть оператор next. В случае с Query это бывает актуально - когда один метод конструирует запрос, а второй - бегает по циклу.
Ага ![]()
__________________
"Страх перед возможностью ошибки не должен отвращать нас от поисков истины." (с) С Уважением, Елизаров Артем |
|
![]() |
#7 |
Axapta
|
Я понимаю, что salesLine.InventTransId по хорошему должен быть непустым, но правильнее сделать все-таки вот так:
X++: void SelectNextSample(salesID _salesID, inventtransID _inventTransID = '') { salesLine salesLine; ; while select salesLine where salesLine.SalesId == _salesID && // (salesLine.InventTransId == _inventTransID || _inventTransID == '') (_inventTransID == '' || salesLine.InventTransId == _inventTransID) { info(salesLine.ItemId); } } |
|
|
За это сообщение автора поблагодарили: lev (1). |
![]() |
#8 |
Ищущий знания...
|
Цитата:
когда писал пример не заострил внимание на логическом построении условия с inventTransId. Конечно лучше вначале проверить заполнена ли переменная с критерием, а потом уже проверить соответствие этой переменной с полем в таблице.
__________________
"Страх перед возможностью ошибки не должен отвращать нас от поисков истины." (с) С Уважением, Елизаров Артем |
|
![]() |
#9 |
Участник
|
Вообще по хорошему вычисление выражения (_inventTransID == '') должно быть выполнено оптимизатором до цикла. И на SQL-сервер должен уйти следующий запрос, который в свою очередь должен быть в итоге соптимизирован до простейшего запроса.
Код: select salesLine where salesLine.SalesId == _salesID && (salesLine.InventTransId == _inventTransID || true) Код: // Оптимизируем select salesLine where salesLine.SalesId == _salesID && true Код: // Ещё раз оптимизируем select salesLine where salesLine.SalesId == _salesID ![]() |
|
![]() |
#10 |
Участник
|
|
|
![]() |
#11 |
Участник
|
Не понимаю наездов на исходный код, он на 100% правильно написан.
1). Если нет взаимодействия с пользователем или сбора query() в подклассах, лучше писать select, чем использовать query() - гораздо наглядней, особенно в отладчике. 2) Приведенная автором блога конструкция гораздно нагляднее всех предложенных альтернатив. 3) Проверка на непустое значение inventTransID присутствует, код корректен. Еще никогда не видел у партнеров код лучше, чем от MS (если не брать некоторые модули, которые MS купил у партнеров), но видел много кода написанного партнерами и клиентами (компания FWI тут приятное исключение, но мы писали не лучше чем в стандарте, просто на уровне, ИМХО), который гораздно хуже кода MS. Поэтому не понимаю ехидства по отношению к автору. |
|
![]() |
#12 |
Ищущий знания...
|
т.е. вы считаете нормальным написания 100 строк кода вместо 5-ти?
а если у программиста дрогнет рука и он забудет про next, тогда сколько мы будем ждать пока код выполниться? когда код избыточен, он менее читаем, это факт. когда код сильно зависим от человеческого фактора (не люблю next-ы) то же не есть гуд. да конечно, код рабочий, но у него много но, ИМХО.
__________________
"Страх перед возможностью ошибки не должен отвращать нас от поисков истины." (с) С Уважением, Елизаров Артем |
|
![]() |
#13 |
Участник
|
Если правильно написан означает компилируется и проходит тесты, то да. Этого здесь никто и не отрицал.
Критику не выдерживает сам подход использования статичестких select'ов против динамического построения Query. Представьте себе, что помимо добавления условия по _inventTransID необходимо станет управлять ну скажем фильтром по InventDimId. Тогда один if разрастётся на 4 ветки: учитываем inventTransID и не учитываем InventDimId не учитываем inventTransID и учитываем InventDimId учитываем inventTransID и учитываем InventDimId не учитываем inventTransID и не учитываем InventDimId А что делать если таких условий ещё больше? И вы действительно считаете что такой код сопровождать легче? |
|
![]() |
#14 |
Участник
|
Процитирую сам себя:
Цитата:
1). Если нет взаимодействия с пользователем или сбора query() в подклассах, лучше писать select, чем использовать query() - гораздо наглядней, особенно в отладчике.
|
|
![]() |
#15 |
Участник
|
To S.Kuskov:
Можно и в методе find() использовать query(), вдруг кто-то через десять лет сделать уникальный ключ составным из 10 полей, тогда query() будет удобней. |
|
![]() |
#16 |
Ищущий знания...
|
я бы сказал не наглядней, а привычней
![]() ![]() + в query более наглядно подставляется критерий в зависимости от его заполнености. например, на мой взгляд, вот это: X++: if (_itemId != '') qbdsInventTable.addRange(fieldNum(InventTable, ItemId)).value(QueryValue(_itemId)); X++: select inventTable where _itemId == '' || inventTable.ItemId == _itemId;
__________________
"Страх перед возможностью ошибки не должен отвращать нас от поисков истины." (с) С Уважением, Елизаров Артем |
|
![]() |
#17 |
Участник
|
To lev:
Там не 100 строк всето 5-ти. Если было бы так - тогда надо что-то придумывать (query или то, что вы предложили). Но для изначально стоящей задачи (метод принимает 2 переменные) - предложенный код самый наглядный и возможно самый быстрый (принимая во внимание замечание S.Kuskov про оптимизатор). |
|
![]() |
#18 |
Ищущий знания...
|
тут говорят про взвешенный подход к написанию кода, а не пропагандируют использования чего либо (в нашем случае query) везде где только возможно, доводя его использование до абсурда.
__________________
"Страх перед возможностью ошибки не должен отвращать нас от поисков истины." (с) С Уважением, Елизаров Артем |
|
![]() |
#19 |
Участник
|
Кроме того, уважаемые участники.
Если бы в этом методе был использован query() - ок Если бы было написано так, как предложил lev - ок Два эти подхода тоже хороши и часто используются, я против них ничего не имею. Просто я считаю, что изначальный вариант не чем не хуже и не стоит на него набрасываться. Притом не понятно с какой стати ехидничать над авторами стандарта, притом что код там очень хорош. |
|
![]() |
#20 |
Ищущий знания...
|
Цитата:
Сообщение от petr
![]() To lev:
Там не 100 строк всето 5-ти. Если было бы так - тогда надо что-то придумывать (query или то, что вы предложили). Но для изначально стоящей задачи (метод принимает 2 переменные) - предложенный код самый наглядный и возможно самый быстрый (принимая во внимание замечание S.Kuskov про оптимизатор). если возможно написать один запрос и в нем обработать нужные условия, зачем писать два запроса, и обрабатывать условия по IF? + написание цикла while становиться опасным, а не забудет ли программист про next?
__________________
"Страх перед возможностью ошибки не должен отвращать нас от поисков истины." (с) С Уважением, Елизаров Артем |
|
|
|