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

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 13.09.2010, 15:58   #21  
sukhanchik is offline
sukhanchik
Administrator
Аватар для sukhanchik
MCBMSS
Злыдни
Лучший по профессии 2015
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
3,311 / 3547 (125) ++++++++++
Регистрация: 13.06.2004
Адрес: Москва
Цитата:
Сообщение от lev Посмотреть сообщение
эээ, а если в какой нибудь из следующих версий вдруг решат увеличить максимальное число элементов в enum-е и сделают например 300? тогда такая доработка сразу внесет много лишней работы при переходе на новую версию.
Учитывая как сильно последнее время отличаются между собой версии - эта "мелочь" потонет при апгрейде. Да и пригодится-то она только в своих модификациях только, которых не должно быть много .
По поводу констант - от их использования никуда не убежишь. И их использование заменяется использованием макросов.
Если бы можно было бы от констант отказаться - то давно б отказались. Не приветствуется использование таких констант, которые не могут быть константами - ставка налога к примеру. А какие-то вещи - типа количество дней в году, или "волшебный номер" 255 - вполне может использоваться. Как раз-таки его и не потребовалось бы использовать - если бы все енумы начинались бы с нулевого ничего не значащего значения.
__________________
Возможно сделать все. Вопрос времени
Старый 13.09.2010, 16:04   #22  
db is offline
db
Роман Долгополов (RDOL)
Лучший по профессии 2015
Лучший по профессии AXAWARD 2013
 
393 / 692 (24) +++++++
Регистрация: 01.04.2004
Адрес: Москва
Цитата:
Сообщение от lev Посмотреть сообщение
Использование констант в X++ не приветствуется.
Именно поэтому их и заворачивают в макросы/стат методы

Для тех кому 255 неприемлемо по религиозным соображениям - кошерная эмуляция NULL с помощью двух parm- методов

MySuperEnum parmMySuperEnum()
boolean parmUseMySuperEnum()
Старый 13.09.2010, 16:05   #23  
lev is offline
lev
Ищущий знания...
Аватар для lev
Oracle
MCBMSS
Axapta Retail User
 
1,723 / 491 (20) +++++++
Регистрация: 18.01.2005
Адрес: Москва
Цитата:
Сообщение от sukhanchik Посмотреть сообщение
Учитывая как сильно последнее время отличаются между собой версии - эта "мелочь" потонет при апгрейде. Да и пригодится-то она только в своих модификациях только, которых не должно быть много .
По поводу констант - от их использования никуда не убежишь. И их использование заменяется использованием макросов.
Если бы можно было бы от констант отказаться - то давно б отказались. Не приветствуется использование таких констант, которые не могут быть константами - ставка налога к примеру. А какие-то вещи - типа количество дней в году, или "волшебный номер" 255 - вполне может использоваться. Как раз-таки его и не потребовалось бы использовать - если бы все енумы начинались бы с нулевого ничего не значащего значения.
понятное дело что от констант не уйти на 100%, но по максимуму их можно сократить
под не использованием нулевого значения, я не имел ввиду создание элементов начиная с 1. Имелось в виду создания Первого элемента как None = 0, которое не имеет смысловой нагрузки, а используется как пустое значение.
__________________
"Страх перед возможностью ошибки не должен отвращать нас от поисков истины." (с)
С Уважением,
Елизаров Артем
Старый 13.09.2010, 16:10   #24  
lev is offline
lev
Ищущий знания...
Аватар для lev
Oracle
MCBMSS
Axapta Retail User
 
1,723 / 491 (20) +++++++
Регистрация: 18.01.2005
Адрес: Москва
Цитата:
Сообщение от db Посмотреть сообщение
Именно поэтому их и заворачивают в макросы/стат методы

Для тех кому 255 неприемлемо по религиозным соображениям - кошерная эмуляция NULL с помощью двух parm- методов

MySuperEnum parmMySuperEnum()
boolean parmUseMySuperEnum()
Все проще Используйте везде в своем коде элемент None (0) как пустой, и тогда не придется писать глобальные методы с цифирками, или эмуляторы NULL

P.S. наше обсуждение ушло немного в сторону от исходной темы, приношу свои извинения топикстартеру
__________________
"Страх перед возможностью ошибки не должен отвращать нас от поисков истины." (с)
С Уважением,
Елизаров Артем
Старый 13.09.2010, 16:11   #25  
sukhanchik is offline
sukhanchik
Administrator
Аватар для sukhanchik
MCBMSS
Злыдни
Лучший по профессии 2015
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
3,311 / 3547 (125) ++++++++++
Регистрация: 13.06.2004
Адрес: Москва
Цитата:
Сообщение от lev Посмотреть сообщение
понятное дело что от констант не уйти на 100%, но по максимуму их можно сократить
Есть вещи (типа кол-во значений в енуме) которые можно принять за "условно постоянные". Почему-то ни у кого не возникает идеи считать к примеру пути к узлам АОТа как не константу. Или коды типов узлов (TreeNodeSysNodeType).

Цитата:
Сообщение от lev Посмотреть сообщение
под не использованием нулевого значения, я не имел ввиду создание элементов начиная с 1. Имелось в виду создания Первого элемента как None = 0, которое не имеет смысловой нагрузки, а используется как пустое значение.
В такой постановке абсолютно согласен.
__________________
Возможно сделать все. Вопрос времени
Старый 13.09.2010, 16:12   #26  
db is offline
db
Роман Долгополов (RDOL)
Лучший по профессии 2015
Лучший по профессии AXAWARD 2013
 
393 / 692 (24) +++++++
Регистрация: 01.04.2004
Адрес: Москва
Цитата:
Сообщение от lev Посмотреть сообщение
Все проще Используйте везде в своем коде элемент None (0) как пустой, и тогда не придется писать глобальные методы с цифирками, или эмуляторы NULL

P.S. наше обсуждение ушло немного в сторону от исходной темы, приношу свои извинения топикстартеру
Да я бы рад, только что делать с каким нибудь, например, SalesType?
Старый 13.09.2010, 16:24   #27  
lev is offline
lev
Ищущий знания...
Аватар для lev
Oracle
MCBMSS
Axapta Retail User
 
1,723 / 491 (20) +++++++
Регистрация: 18.01.2005
Адрес: Москва
Цитата:
Сообщение от db Посмотреть сообщение
Да я бы рад, только что делать с каким нибудь, например, SalesType?
ждал этого вопроса
если вам нужно выполнить обработку по заказам, и эта обработка должна быть параметризирована, то я бы для обработки создал свой Enum, с помощью которого бы определялось, выполнять обработку по заказам с SalesType = Journal или Sales.
Конечно это более трудозатратно чем просто передать в параметре SalesType, но в случае с уже существующими (системными) enum-ами, где нулевой элемент несет смысловую нагрузку, это гарантирует что все проверки по параметру отработаю корректно, и все необходимые заказы будут обработаны. Вот как то так
__________________
"Страх перед возможностью ошибки не должен отвращать нас от поисков истины." (с)
С Уважением,
Елизаров Артем
Старый 13.09.2010, 16:33   #28  
db is offline
db
Роман Долгополов (RDOL)
Лучший по профессии 2015
Лучший по профессии AXAWARD 2013
 
393 / 692 (24) +++++++
Регистрация: 01.04.2004
Адрес: Москва
Цитата:
Сообщение от lev Посмотреть сообщение
ждал этого вопроса
если вам нужно выполнить обработку по заказам, и эта обработка должна быть параметризирована, то я бы для обработки создал свой Enum, с помощью которого бы определялось, выполнять обработку по заказам с SalesType = Journal или Sales.
Конечно это более трудозатратно чем просто передать в параметре SalesType, но в случае с уже существующими (системными) enum-ами, где нулевой элемент несет смысловую нагрузку, это гарантирует что все проверки по параметру отработаю корректно, и все необходимые заказы будут обработаны. Вот как то так
Ну это и есть "вид сбоку" для кошерного варианта с двумя parm-методами. Доп parm метод или новый енум, объединяющий в себе и галку и собственно тип. Лично я все таки предпочту не засорять AOT одноразовыми енумами

Идеального универсального решения для этой задачи нет. Выбираем на свой вкус и пользуемся при необходимости. Вкусы можно менять в зависимости от ситуации

Предлагаю на этом закончить
Старый 13.09.2010, 16:57   #29  
titov is offline
titov
Участник
 
73 / 87 (3) ++++
Регистрация: 23.12.2005
Адрес: Казань
Цитата:
Сообщение от db Посмотреть сообщение
Завести где нито макрос/метод класса/глобальную функцию которая это будет возвращать и в нужных местах инициализировать/сравнивать. 255 не может быть у енума
AOT\Macros\Axd - строка #define.axdUnknownEnumValue(255) - уже есть!
За это сообщение автора поблагодарили: db (1), sukhanchik (3).
Старый 20.06.2011, 15:19   #30  
leva is offline
leva
Участник
 
52 / 36 (2) +++
Регистрация: 03.08.2005
В сто пятидесятый раз попал в туже ситуацию и решил разобраться в вопросе.
Итак, изначальная постановка Wamr была: как правильно реализовать серверный обработчик (плюс который нормально будет работать в пакете) с параметрами, изменяемыми в диалоге. Само собой этот параметр будет в списке тех, которые сохраняются в pack() и поэтому если мы этот параметр parm-методом зададим он перетрётся старым значением.

Есть предложение db писать в таких случаях в main():
.getLast()
.parmXXX(...)
.saveLast()

Я так тоже делал, но такой метод мне не нравится, так как во-первых, сохраняет уже сразу после вызова, даже если мы отменим выполнение в диалоге и во-вторых, если класс сделан с запросом на QueryRun (который сохраняется в pack()), то нужно уже на этом этапе как-то его инициализировать.

sukhanchik предложил просто такие параметры не "распаковывать" если они не пусты, признав далее извращенность такого решения. И далее дискуссия ушла в обсуждение Enum-ов, чего касаться я вообще не хочу.

Собственно я предлагаю такой вариант:
1. В classDeclaration добавить макрос со списком параметров, которые будут меняться в диалоге, например:
X++:
    #localmacro.ParamsList
        param1,
        param2
    #endmacro
2. В unpack() сохранять эти значения в контейнер и в случае, если метод был вызван для загрузки старых значений (определяется методом this.inGetSaveLast()) восстанавливать их, например:
X++:
public boolean unpack(container packedClass)
{
    Version version     = runbase::getVersion(packedClass);
    container   params = [#ParamsList];

    switch (version)
    {
        case #CurrentVersion:
            [version,#CurrentList] = packedClass;
            if (this.inGetSaveLast())
                [#ParamsList] = params;
            break;
        default:
            return false;
    }

    return true;
}
Таким образом, при загрузке значений клиентской копией и при создании объекта пакетного задания (в этих случаях inGetSaveLast = false) загрузится всё из упакованного контейнера, а случае запуска из меню с определёнными параметрами эти параметры не перетрутся.
Единственное надо проверить, чтобы на всех версиях аксапты параметр inGetSaveLast вёл себя одинаково. Ну и в минусы можно записать то, что этот список нужно не забывать пополнять по мере доработки класса (версионность тут вроде не нужна).

Подводных камней вроде не вижу. Что скажете?
Старый 20.06.2011, 15:29   #31  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,941 / 3229 (115) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
2 leva
А не проще написать свой конструктор, а в нем :
X++:
static construct()
{
    ret = New runBase_...child();
    ;
    ret.getLast();
    return ret;
}
а затем в main вместо New runBase_...child()
писать
runBase_...child::construct()

всегда так делаю и проблем вроде не было.
плюс так правильнее писать. В дальнейшем легче код поддерживать если потребуется везде использовать другого наследника. подправил contruct и все.
Старый 20.06.2011, 15:46   #32  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,941 / 3229 (115) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
Т.е. идея в том что вы сперва все параметры распаковали, а потом уже поверх них записали все параметры, какие надо. Сохранения сразу после вызова при таком подходе тоже нет. (Хотя не вижу в нем ничего плохого. Кому оно может помешать ?)
Старый 20.06.2011, 15:50   #33  
leva is offline
leva
Участник
 
52 / 36 (2) +++
Регистрация: 03.08.2005
Ну и дальше что? Вызываем prompt() который опять перетирает все параметры.
Старый 20.06.2011, 15:58   #34  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,941 / 3229 (115) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
Цитата:
Сообщение от leva Посмотреть сообщение
Ну и дальше что? Вызываем prompt() который опять перетирает все параметры.
Не должен перетирать, потому что в конструкторе уже вызван getLast()
Он при вызове getLast() взводит некий флажок. Так что при вызове Prompt() повторного вызова getLast() и, соответственно, перезатирания не происходит.
За это сообщение автора поблагодарили: leva (1).
Старый 20.06.2011, 16:27   #35  
leva is offline
leva
Участник
 
52 / 36 (2) +++
Регистрация: 03.08.2005
Цитата:
Сообщение от Logger Посмотреть сообщение
Он при вызове getLast() взводит некий флажок.
Действительно, и как я не заметил. И почему-то такое, лежащее на поверхности решение, тогда никто не предложил.

Но есть правда один момент, бывает что в unpack создается queryRun, который в свою очередь может зависеть от этого параметра. Тут конечно можно вызвать перестроение запроса после всех parm-ов, но хотелось бы не выносить заботу о таких вещах из класса.

Ну и подводный камень в своем решении нашел - если getLast() будет вызван ни для заполнения формочки, а с какой-то другой целью в этих параметрах будет пустота.
Старый 20.06.2011, 16:38   #36  
leva is offline
leva
Участник
 
52 / 36 (2) +++
Регистрация: 03.08.2005
Нашёл как обойти подводный камень с неверным поведением unpack в других случаях - нужно добавить к this.inGetSaveLast() && inPrompt

Может показаться, что я тут фигней занимаюсь, но хочется написать универсальную, красивую и максимально корректную рыбу, чтобы голову больше этим не забивать.
Старый 20.06.2011, 17:36   #37  
Владимир Максимов is offline
Владимир Максимов
Участник
КОРУС Консалтинг
 
1,691 / 1195 (43) ++++++++
Регистрация: 13.01.2004
Записей в блоге: 3
Ну, если решение через Construct - не нравится, то можно пойти "другим путем"

Если сделать допущение, что имя параметра вовсе не обязано совпадать с именем сохраняемой в pack/unpack переменной, то все решается значительно проще.

Через parmXXX() записываем переменную parmXXX, а в методе RunBase.dialog() при создании объектов формы диалога пишем примерно следующее

X++:
dialogField = dialog.addFieldValue(typeid(MyType), parmXXX ? parmXXX : unpackYYY);
Собственно, на этом и все модификации заканчиваются.

Если передан параметр (parmXXX), то он инициализирует значение объекта на форме диалога и он же будет сохранен, если пользователь его не изменит. Если же параметр не передан, то инициализировать значение объекта на форме диалога будет распакованное значение переменной.

С Query - чуть сложнее, но тоже не особо. Ведь в любом случае должен быть метод по его созданию. Вот в этом методе и анализировать значение параметра.

В любом случае "разведение" переданных и сохраненных значений по разным переменным значительно упростит как анализ, так и кодирование.
За это сообщение автора поблагодарили: S.Kuskov (2).
Старый 21.06.2011, 08:15   #38  
leva is offline
leva
Участник
 
52 / 36 (2) +++
Регистрация: 03.08.2005
Цитата:
Сообщение от Владимир Максимов Посмотреть сообщение
Если передан параметр (parmXXX), то он инициализирует значение объекта на форме диалога и он же будет сохранен, если пользователь его не изменит.
Т.е. мало того, что вводятся дублирующие параметры, так ещё и принимается, что если что-то пусто, то оно не инициализировано. Нет, это не выход и это уже здесь обсуждалось. И с тем, что это что-то упростит я не согласен.

Цитата:
Сообщение от Владимир Максимов Посмотреть сообщение
С Query - чуть сложнее, но тоже не особо. Ведь в любом случае должен быть метод по его созданию. Вот в этом методе и анализировать значение параметра.
В том то и дело, что такой метод есть. Только не забываем, что этот query как правило выводится в диалоге и может быть там изменён. А значит, нужно этот метод вызвать после того как новые parm-параметры заданы, но перед тем как они будут упакованы и отправлены клиентскому объекту (мне пришёл в голову только вариант переопределить prompt и перез super() вызвать.) Либо вызывать при каждом unpack, что добавляет два лишних перестроения этого запроса (даже больше, если это будет пакетным заданием). В моем варианте это делается один раз.

Вот мой вариант с Query. Здесь initQuery тот самый метод, что строит запрос (на основе переданного в качестве параметра).

X++:
public boolean unpack(container packedClass)
{
    Version     version = runbase::getVersion(packedClass);
    container   packedQuery;
    Query       query;
    container   params = [#ParamsList];

    switch (version)
    {
        case #CurrentVersion:
            [version, #CurrentList, packedQuery] = packedClass;
            if (packedQuery && SysQuery::isPackedOk(packedQuery))
                query = new Query(packedQuery);
            if (! query)
                throw error("Ошибка");

            if (inPrompt && inGetSaveLast)
            {
                [#ParamsList] = params;
                queryRun = new QueryRun(this.initQuery(query));
            }
            else
                queryRun = new QueryRun(query);

            break;

        default:
            return false;
    }

    return true;
}
Старый 21.06.2011, 08:59   #39  
S.Kuskov is offline
S.Kuskov
Участник
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
 
3,438 / 1775 (66) ++++++++
Регистрация: 28.04.2007
Адрес: Калуга
Цитата:
Сообщение от Wamr Посмотреть сообщение
1. Есть некий серверный обработчик, который вызывается из основного меню и из формы
Мне кажеться логичным в принципе разделить и не смешивать эти два случая, а точнее не смешивать сами сохраняемые значения. Пусть при запуске через форму будет вестись своя история последних значений, а при запуске из главного меню - своя. Для этого достаточно переопределить один из методов интерфейса SysSaveable (например: lastValueType), в котором возвращать параметр передавыемый через менюайтем и не париться по поводу ручного разруливания сохранённых значений.
Старый 21.06.2011, 10:00   #40  
Владимир Максимов is offline
Владимир Максимов
Участник
КОРУС Консалтинг
 
1,691 / 1195 (43) ++++++++
Регистрация: 13.01.2004
Записей в блоге: 3
leva

Описанная задача не то, чтобы совсем уж невозможная, но достаточно экзотическая. sukhanchik уже пытался намекнуть на это. Да и S.Kuskov говорит о том же. Ну, не может один и тот же класс и принимать значение из-вне и доставать это же самое значение из кеша. Не в смысле того, что физически не может, а в том смысле, что подобная задача свидетельствует о том, что у Вас большие проблемы в организации структуры классов.

Как минимум, это должно быть два разных класса. Один - предназначенный для извлечения значения параметра из кеша, а другой - для приема параметров из-вне класса. И попытка "смешать" две разные задачи в одном классе ничего кроме проблем Вам не принесет.

Не надо пытаться сделать один супер-класс на все случаи жизни. Не то, чтобы это было совсем уж невозможно, но практического смысла в этом нет. Два отдельных класса и проще сделать, и проще сопровождать.
 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
Глюк RunBase (AX40sp2) Alexx7 DAX: Программирование 7 22.01.2010 10:59
Inside Dynamics AX 4.0: RunBase Framework Extension Part IV Blog bot DAX Blogs 0 02.10.2007 04:49
Inside Dynamics AX 4.0: RunBase Framework Extension Part III Blog bot DAX Blogs 0 02.10.2007 04:49
Inside Dynamics AX 4.0: RunBase Framework Extension Part I Blog bot DAX Blogs 0 30.09.2007 09:20
Некоторые вопросы внедрения приложений. Часть 2 Михаил Ковалев DAX: Прочие вопросы 0 27.05.2002 10:43
Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

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

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

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