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

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 13.07.2017, 14:51   #1  
AfterEarth is offline
AfterEarth
Участник
 
12 / 10 (1) +
Регистрация: 13.07.2017
Адрес: Санкт-Петербург
Значения переменных по имени при подстановке в данные запроса
Здравствуйте!
Искал поиском и в помощи, но ничего, кроме EvalBuf не нашёл, а он не работает с переменными.
Есть задача - сделать запрос с динамическими данными -выбирать значения из переменных для insert в зависимости от описания и имён полей, а также переменных по имени из таблицы.
Это выгрузки в различные форматы, чтобы не писать на каждую выгрузку свою функцию.

Что-то типа: "insert 'insert into tablename (FIELD1, FIELD2,etc..... VALUES (%1,%2,etc....),
EvalBuf('var1'),EvalBuf('var2'),etc....

Строковые значения для формирования строки запроса 'FIELD1', 'FIELD2', 'var1', "var2" берутся из таблицы, а сами переменные var1,var2 объявляются в классе

Заранее спасибо за ответ! Отблагодарю за реальную помощь!

Последний раз редактировалось AfterEarth; 13.07.2017 в 14:58. Причина: Не проставил теги, но нашёл, как их поставить :(
Старый 13.07.2017, 15:20   #2  
raz is offline
raz
NavAx
Аватар для raz
NavAx Club
Лучший по профессии 2014
Лучший по профессии 2009
 
1,490 / 1060 (38) ++++++++
Регистрация: 22.07.2003
Адрес: МО
Извиняюсь, а про strFmt() знаете?
Посмотрите классы ReleaseUpdateDB*...

Последний раз редактировалось raz; 13.07.2017 в 15:22.
Старый 13.07.2017, 15:42   #3  
AfterEarth is offline
AfterEarth
Участник
 
12 / 10 (1) +
Регистрация: 13.07.2017
Адрес: Санкт-Петербург
Цитата:
Сообщение от raz Посмотреть сообщение
Извиняюсь, а про strFmt() знаете?
Знаю, как и про RunBuf. Там нужны именно переменные в параметрах, а у меня имя переменной может меняться. Фишка в том, чтобы не описывать имена этих переменных в коде, а брать из БД. В Clipper'е это было eval('Переменная'). Нашёл для DAX2 this['Переменная'] = что-то, но в DAX3 оно не работает

Цитата:
Сообщение от raz Посмотреть сообщение
Посмотрите классы ReleaseUpdateDB*...
Посмотрел его в помощи, но не понял, чем он может помочь
Старый 13.07.2017, 16:09   #4  
raz is offline
raz
NavAx
Аватар для raz
NavAx Club
Лучший по профессии 2014
Лучший по профессии 2009
 
1,490 / 1060 (38) ++++++++
Регистрация: 22.07.2003
Адрес: МО
Сохраните имена переменных в таблицу, set, map, list...
Старый 13.07.2017, 16:22   #5  
ax_mct is offline
ax_mct
Banned
 
2,548 / 1091 (0) ++++++++
Регистрация: 10.10.2005
Адрес: Westlands
Цитата:
Сообщение от AfterEarth Посмотреть сообщение
Здравствуйте!
Искал поиском и в помощи, но ничего, кроме EvalBuf не нашёл, а он не работает с переменными.
Есть задача - сделать запрос с динамическими данными -выбирать значения из переменных для insert в зависимости от описания и имён полей, а также переменных по имени из таблицы.
Это выгрузки в различные форматы, чтобы не писать на каждую выгрузку свою функцию.

Что-то типа: "insert 'insert into tablename (FIELD1, FIELD2,etc..... VALUES (%1,%2,etc....),
EvalBuf('var1'),EvalBuf('var2'),etc....

Строковые значения для формирования строки запроса 'FIELD1', 'FIELD2', 'var1', "var2" берутся из таблицы, а сами переменные var1,var2 объявляются в классе

Заранее спасибо за ответ! Отблагодарю за реальную помощь!
А если будет копи-паст, то сколько этих функций? По-честному, а?
Старый 13.07.2017, 16:32   #6  
raz is offline
raz
NavAx
Аватар для raz
NavAx Club
Лучший по профессии 2014
Лучший по профессии 2009
 
1,490 / 1060 (38) ++++++++
Регистрация: 22.07.2003
Адрес: МО
Кажется понял, что нужно...
X++:
class myClass
{
    var Var1;
    var Var2;


    void myInsert()
    {
         :
        str statement = strfmt('insert into tablename (FIELD1, FIELD2,etc..... VALUES (%1,%2,etc....)',
EvalBuf('var1'),EvalBuf('var2'),);
    }
}
Замените var Var1 ... var VarN на таблицу myVarsTable или map.

Ну и в конструкции strfmt('insert into tablename (FIELD1, FIELD2,etc..... VALUES (%1,%2,etc....)',
EvalBuf('var1'),EvalBuf('var2'),); можно просто заменить EvalBuf('var1') на var1 - strfmt('insert into tablename (FIELD1, FIELD2,etc..... VALUES (%1,%2,etc....)',
var1,var2,...);
Старый 13.07.2017, 16:32   #7  
Товарищ ♂uatr is offline
Товарищ ♂uatr
Участник
Аватар для Товарищ ♂uatr
MCBMSS
 
265 / 808 (27) +++++++
Регистрация: 23.10.2012
Экспериментальный код:
X++:
void insertToDB(Common _common)
{
    Common                                          commonOrig;
    System.Data.SqlClient.SqlCommand                sqlCommand;
    System.Data.SqlClient.SqlConnection             sqlConnection;
    System.Data.SqlClient.SqlParameterCollection    parameterCollection;
    System.Data.SqlClient.SqlParameter              sqlParameter;
    System.Byte[]                                   bytes;
    SysSQLSystemInfo                                SQLSystemInfo = SysSQLSystemInfo::construct();
    DictTable                                       dictTable;
    int                                             j;
    DictField                                       dictField;
    str                                             fieldsStr,
                                                    valuesStr,
                                                    parameterId;
    Map                                             valuesMap,
                                                    sizeMap;
    AnyTypeValue                                    AnyTypeValue;
    MapEnumerator                                   valuesMapEnumerator;
    System.IO.MemoryStream                          memStream;
    RecId                                           ret;
    TreeNode                                        treeNode;
    str                                             insertStr;
    #AOT
    ;

    dictTable = new DictTable(_common.TableId);
    valuesMap = new Map(Types::Integer, Types::Class);
    sizeMap   = new Map(Types::Integer, Types::Integer);

    for (j = 1; j <= dictTable.fieldCnt(); j++)
    {
        dictField = new DictField(_common.TableId, dictTable.fieldCnt2Id(j));

        if (!dictField.isSql() || !_common.(dictField.id()))
        {
            continue;
        }

        if (dictField)
        {
            if (dictField.baseType() == Types::String)
            {
                sizeMap.insert(j, dictField.stringLen());
            }

            if (fieldsStr)
            {
                fieldsStr += strFmt(',[%1]', dictField.name(DbBackend::Sql));
                valuesStr += strFmt(',@FLD%1', j);
            }
            else
            {
                fieldsStr = strFmt('[%1]', dictField.name(DbBackend::Sql));
                valuesStr = strFmt('@FLD%1', j);
            }

            AnyTypeValue = new AnyTypeValue(_common.(dictField.id()));

            if (dictField.name() == identifierStr(RecId))
            {
                ret = AnyTypeValue.value();
            }

            valuesMap.insert(j, AnyTypeValue);
        }
    }

    sqlConnection = new System.Data.SqlClient.SqlConnection(strFmt("Data Source=%1;Initial Catalog=%2;Integrated Security=True",
                                                                   SQLSystemInfo.getLoginServer(),
                                                                   SQLSystemInfo.getloginDatabase()));

    sqlCommand    = new System.Data.SqlClient.SqlCommand(strFmt('INSERT INTO %1 (%2) VALUES (%3)', dictTable.name(DbBackend::Sql), fieldsStr, valuesStr), sqlConnection);



    parameterCollection = sqlCommand.get_Parameters();

    valuesMapEnumerator = valuesMap.getEnumerator();

    while (valuesMapEnumerator.moveNext())
    {
        parameterId  = strFmt('@FLD%1', valuesMapEnumerator.currentKey());
        AnyTypeValue = valuesMapEnumerator.currentValue();

        switch (AnyTypeValue.typeOf())
        {
            case Types::Enum    :
                sqlParameter = parameterCollection.Add(parameterId, System.Data.SqlDbType::Int);
                sqlParameter.set_Value(enum2int(AnyTypeValue.value()));
                break;

            case Types::Time    :
            case Types::Integer :
                sqlParameter = parameterCollection.Add(parameterId, System.Data.SqlDbType::Int);
                sqlParameter.set_Value(AnyTypeValue.value());
                break;

            case Types::Int64    :
                sqlParameter = parameterCollection.Add(parameterId, System.Data.SqlDbType::BigInt);
                sqlParameter.set_Value(AnyTypeValue.value());
                break;

            case Types::Guid    :
                sqlParameter = parameterCollection.Add(parameterId, System.Data.SqlDbType::UniqueIdentifier);
                sqlParameter.set_Value(AnyTypeValue.value());
                break;

            case Types::Real    :
                sqlParameter = parameterCollection.Add(parameterId, System.Data.SqlDbType::Real);
                sqlParameter.set_Value(AnyTypeValue.value());
                break;

            case Types::Date        :
            case Types::UtcDateTime :
                sqlParameter = parameterCollection.Add(parameterId, System.Data.SqlDbType::DateTime);
                sqlParameter.set_Value(AnyTypeValue.value());
                break;

            case Types::String    :
                if (sizeMap.exists(valuesMapEnumerator.currentKey()))
                {
                    sqlParameter = parameterCollection.Add(parameterId, System.Data.SqlDbType::NVarChar, sizeMap.lookup(valuesMapEnumerator.currentKey()));
                }
                else
                {
                    sqlParameter = parameterCollection.Add(parameterId, System.Data.SqlDbType::NVarChar, -1);
                }

                sqlParameter.set_Value(AnyTypeValue.value());
                break;

            case Types::BLOB :
                sqlParameter = parameterCollection.Add(parameterId, System.Data.SqlDbType::VarBinary);
                memStream = Binary::constructFromContainer(AnyTypeValue.value()).getMemoryStream();
                bytes = memStream.ToArray();
                memStream.Close();
                sqlParameter.set_Value(bytes);
            case Types::Container :
                sqlParameter = parameterCollection.Add(parameterId, System.Data.SqlDbType::VarBinary);
                memStream = Binary::constructFromContainer(new ContainerClass(AnyTypeValue.value()).toBlob()).getMemoryStream();
                bytes = memStream.ToArray();
                memStream.Close();
                sqlParameter.set_Value(bytes);
                break;
            default :
                sqlParameter = parameterCollection.Add(parameterId, AnyTypeValue.value());
                break;
        }
    }

    if (memStream)
    {
        memStream.Dispose();
    }

    sqlConnection.Open();

    sqlCommand.ExecuteNonQuery();
    sqlCommand.Dispose();

    sqlConnection.Close();
    sqlConnection.Dispose();
}
На вход принимает xRecord объект с проинициализированными значениями полей, вставляет запись в БД.
Табличный метод insert может быть перекрыт. Решайте сами нужно ли выполнять этот код.
Аналогичная ситуация со ставкой записи в ЖБД
X++:
new Application().logInsert(_common);
За это сообщение автора поблагодарили: trud (5), AfterEarth (1).
Старый 13.07.2017, 17:10   #8  
AfterEarth is offline
AfterEarth
Участник
 
12 / 10 (1) +
Регистрация: 13.07.2017
Адрес: Санкт-Петербург
Цитата:
Сообщение от raz Посмотреть сообщение
Сохраните имена переменных в таблицу, set, map, list...
А дальше что с ними делать? Мне значения их по имени нужны
Старый 13.07.2017, 17:11   #9  
AfterEarth is offline
AfterEarth
Участник
 
12 / 10 (1) +
Регистрация: 13.07.2017
Адрес: Санкт-Петербург
Цитата:
Сообщение от ax_mct Посмотреть сообщение
А если будет копи-паст, то сколько этих функций? По-честному, а?
Уже "наколбашено" штук 15 и ещё 15 нужно, а потом будут ещё. Смысле копипаст делать? Не по программистки это :-/
Старый 13.07.2017, 17:16   #10  
AfterEarth is offline
AfterEarth
Участник
 
12 / 10 (1) +
Регистрация: 13.07.2017
Адрес: Санкт-Петербург
Цитата:
Сообщение от raz Посмотреть сообщение
Кажется понял, что нужно...
X++:
class myClass
{
    var Var1;
    var Var2;


    void myInsert()
    {
         :
        str statement = strfmt('insert into tablename (FIELD1, FIELD2,etc..... VALUES (%1,%2,etc....)',
EvalBuf('var1'),EvalBuf('var2'),);
    }
}
Замените var Var1 ... var VarN на таблицу myVarsTable или map.

Ну и в конструкции strfmt('insert into tablename (FIELD1, FIELD2,etc..... VALUES (%1,%2,etc....)',
EvalBuf('var1'),EvalBuf('var2'),); можно просто заменить EvalBuf('var1') на var1 - strfmt('insert into tablename (FIELD1, FIELD2,etc..... VALUES (%1,%2,etc....)',
var1,var2,...);
Описание класса правильное, но вместо var1 и var2 могут быть другие переменные. EvalBuf написан для примера - он бы подошёл, если-бы умел не только вычислять (2+3)*5, а возвращать значение переменной по имени.
Имена полей и переменных хранятся в таблице и идея составлять из них запросы в одной строке динамически. Какая именно переменная там будет неизвестно.
Прошу прощения, если непонятно написал....
Старый 13.07.2017, 17:42   #11  
raz is offline
raz
NavAx
Аватар для raz
NavAx Club
Лучший по профессии 2014
Лучший по профессии 2009
 
1,490 / 1060 (38) ++++++++
Регистрация: 22.07.2003
Адрес: МО
Почему map не подходит, где ключ - это имя переменной?

X++:
    Map myVars = new Map(types::string, types::string);

    myVars.insert('Val1', '10.5');
    myVars.insert('Val2', 'Ivanov');

    strfmt('insert into tablename (FIELD1, FIELD2,etc..... VALUES (%1,%2,etc....)', myVars.lookup('Val1'), myVars.lookup('Val2'),...);
или

X++:
    Map myVars = new Map(types::string, types::container);

    myVars.insert('Val1', [10.5]);
    myVars.insert('Val2', ['Ivanov']);

    strfmt('insert into tablename (FIELD1, FIELD2,etc..... VALUES (%1,%2,etc....)', conpeek(myVars.lookup('Val1'), 1), conpeek(myVars.lookup('Val2'), 1),...);
За это сообщение автора поблагодарили: AfterEarth (1).
Старый 13.07.2017, 17:49   #12  
AfterEarth is offline
AfterEarth
Участник
 
12 / 10 (1) +
Регистрация: 13.07.2017
Адрес: Санкт-Петербург
Цитата:
Сообщение от Товарищ ♂uatr Посмотреть сообщение
Экспериментальный код:
X++:
void insertToDB(Common _common)
{
   ....
    AnyTypeValue                                    AnyTypeValue;
  ...
}
Похоже это то, что мне нужно, но что такое AnyTypeValue? Прошу прощения за "чайниковский" вопрос - Аксаптой занимаюсь недавно.... DAX3
Старый 13.07.2017, 17:53   #13  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,867 / 3123 (112) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
Возможно я чего то не понимаю.
А зачем insert into через EvalBuf

Почему не использовали RecordInsertList
Он должен оптимальнее работать.

Заодно можно через common работать с любым типом буфера.
Старый 13.07.2017, 17:54   #14  
AfterEarth is offline
AfterEarth
Участник
 
12 / 10 (1) +
Регистрация: 13.07.2017
Адрес: Санкт-Петербург
Цитата:
Сообщение от raz Посмотреть сообщение
Почему map не подходит, где ключ - это имя переменной?

X++:
    Map myVars = new Map(types::string, types::string);

    myVars.insert('Val1', '10.5');
    myVars.insert('Val2', 'Ivanov');

    strfmt('insert into tablename (FIELD1, FIELD2,etc..... VALUES (%1,%2,etc....)', myVars.lookup('Val1'), myVars.lookup('Val2'),...);
или

X++:
    Map myVars = new Map(types::string, types::container);

    myVars.insert('Val1', [10.5]);
    myVars.insert('Val2', ['Ivanov']);

    strfmt('insert into tablename (FIELD1, FIELD2,etc..... VALUES (%1,%2,etc....)', conpeek(myVars.lookup('Val1'), 1), conpeek(myVars.lookup('Val2'), 1),...);
Переменные объявлены в classDeclarition и мне нужно по их имени получить значения инициализированной в методе переменной, а не данные из таблицы. У Вас в таблицу пойдёт значение из map. Хотя нет-туплю - если переменные описаны в классе, то после их инициализации можно заполнять их значением map.
Спасибо, попробую!
Старый 13.07.2017, 17:57   #15  
AfterEarth is offline
AfterEarth
Участник
 
12 / 10 (1) +
Регистрация: 13.07.2017
Адрес: Санкт-Петербург
Цитата:
Сообщение от Logger Посмотреть сообщение
Возможно я чего то не понимаю.
А зачем insert into через EvalBuf

Почему не использовали RecordInsertList
Он должен оптимальнее работать.

Заодно можно через common работать с любым типом буфера.
Ещё "чайник" в Аксапте. Поэтому приветствуются любые решения. EvalBuf вообще не работает с переменными, только с выражениями. Завтра "покурю" Ваш совет по мануалам.
Старый 13.07.2017, 18:01   #16  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,867 / 3123 (112) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
Цитата:
Сообщение от AfterEarth Посмотреть сообщение
Ещё "чайник" в Аксапте. Поэтому приветствуются любые решения. EvalBuf вообще не работает с переменными, только с выражениями. Завтра "покурю" Ваш совет по мануалам.
https://cse.google.com/cse?cx=017570...ist&gsc.page=1
За это сообщение автора поблагодарили: AfterEarth (1).
Старый 13.07.2017, 18:58   #17  
ax_mct is offline
ax_mct
Banned
 
2,548 / 1091 (0) ++++++++
Регистрация: 10.10.2005
Адрес: Westlands
Цитата:
Сообщение от AfterEarth Посмотреть сообщение
Есть задача - сделать запрос с динамическими данными -выбирать значения из переменных для insert в зависимости от описания и имён полей, а также переменных по имени из таблицы.
Это выгрузки в различные форматы, чтобы не писать на каждую выгрузку свою функцию.
...
Уже "наколбашено" штук 15 и ещё 15 нужно, а потом будут ещё. Смысле копипаст делать? Не по программистки это :-/
Если вы сидите на клиенте как постоянный программист и просто от скуки извращаетесь, то конечно можно все.

Если вы же профессионал, то за такое программирование надо бить, а потом еще раз бить.
Это программизм небитого энтузиаста, а не программирование.
Если есть общее - выделите в родительский класс, если нет сделайте как набор статических методов.
Пусть их будет 50 методов или 50 классов - вам всем скажут только спасибо, а не будут проклинать.
За это сообщение автора поблагодарили: ta_and (4).
Старый 13.07.2017, 19:22   #18  
ta_and is offline
ta_and
Участник
 
226 / 122 (5) +++++
Регистрация: 26.02.2002
Адрес: СПб
Цитата:
Сообщение от ax_mct Посмотреть сообщение
за такое программирование надо бить, а потом еще раз бить.
Абсолютно согласен.
Извращаться для себя чисто в образовательном плане можно сколько угодно.
Но если это делать в рабочем приложении... то это жесть.

Попробуйте сделать нормальную постановку задачи и тогда будет видно грамотное архитектурное решение без всяких чесаний инсертов через ранбуф.

Последний раз редактировалось ta_and; 13.07.2017 в 19:24.
За это сообщение автора поблагодарили: ax_mct (5).
Старый 13.07.2017, 20:35   #19  
dech is offline
dech
Участник
Аватар для dech
Самостоятельные клиенты AX
 
642 / 347 (13) ++++++
Регистрация: 25.06.2009
Адрес: Омск
Записей в блоге: 3
Поскольку не очень понятно, что вы пытаетесь сделать, опубликуйте здесь часть вашего кода. А мы подправим, или направим на путь истинный.
P.S. Посмотрите также в сторону AIF. Об этом можно почитать в книге "MS Dynamics AX 4.0 Справочник профессионала".
__________________
// no comments
Старый 17.07.2017, 12:18   #20  
AfterEarth is offline
AfterEarth
Участник
 
12 / 10 (1) +
Регистрация: 13.07.2017
Адрес: Санкт-Петербург
Цитата:
Сообщение от ax_mct Посмотреть сообщение
Если вы сидите на клиенте как постоянный программист и просто от скуки извращаетесь, то конечно можно все.

Если вы же профессионал, то за такое программирование надо бить, а потом еще раз бить.
Это программизм небитого энтузиаста, а не программирование.
Если есть общее - выделите в родительский класс, если нет сделайте как набор статических методов.
Пусть их будет 50 методов или 50 классов - вам всем скажут только спасибо, а не будут проклинать.
"Если вы же профессионал, то за такое программирование надо бить, а потом еще раз бить." - вот и я так -же решил и стал переделывать. Это до меня было сделано.
 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
где хранятся значения полей удаленных строк? chanchala DAX: Программирование 16 04.09.2008 10:45
Присвоение значения полю активной записи по его имени HorrR DAX: Программирование 9 06.06.2008 12:13
Теряются данные при переносе с 3-ки на 4-ку Stella DAX: Администрирование 8 20.02.2008 19:26
Как получить значения полей (modifiedDate, modifiedTime, modifiedBy и др.) при работе с объектами AOT типа Map? LRA DAX: База знаний и проекты 15 02.04.2007 13:37
Вставка значения container в план запроса SQL mit DAX: Программирование 4 24.11.2005 18:42
Опции темы Поиск в этой теме
Поиск в этой теме:

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

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

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

Рейтинг@Mail.ru
Часовой пояс GMT +3, время: 20:41.
Powered by vBulletin® v3.8.5. Перевод: zCarot
Контактная информация, Реклама.