13.07.2017, 14:51 | #1 |
Участник
|
Значения переменных по имени при подстановке в данные запроса
Здравствуйте!
Искал поиском и в помощи, но ничего, кроме 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 |
NavAx
|
Извиняюсь, а про strFmt() знаете?
Посмотрите классы ReleaseUpdateDB*... Последний раз редактировалось raz; 13.07.2017 в 15:22. |
|
13.07.2017, 15:42 | #3 |
Участник
|
Знаю, как и про RunBuf. Там нужны именно переменные в параметрах, а у меня имя переменной может меняться. Фишка в том, чтобы не описывать имена этих переменных в коде, а брать из БД. В Clipper'е это было eval('Переменная'). Нашёл для DAX2 this['Переменная'] = что-то, но в DAX3 оно не работает
Посмотрел его в помощи, но не понял, чем он может помочь |
|
13.07.2017, 16:09 | #4 |
NavAx
|
Сохраните имена переменных в таблицу, set, map, list...
|
|
13.07.2017, 16:22 | #5 |
Banned
|
Цитата:
Сообщение от 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 |
NavAx
|
Кажется понял, что нужно...
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'),); } } Ну и в конструкции 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 |
Участник
|
Экспериментальный код:
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(); } Табличный метод insert может быть перекрыт. Решайте сами нужно ли выполнять этот код. Аналогичная ситуация со ставкой записи в ЖБД X++: new Application().logInsert(_common); |
|
|
За это сообщение автора поблагодарили: trud (5), AfterEarth (1). |
13.07.2017, 17:10 | #8 |
Участник
|
|
|
13.07.2017, 17:11 | #9 |
Участник
|
|
|
13.07.2017, 17:16 | #10 |
Участник
|
Цитата:
Сообщение от 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'),); } } Ну и в конструкции 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, 17:42 | #11 |
NavAx
|
Почему 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 |
Участник
|
|
|
13.07.2017, 17:53 | #13 |
Участник
|
Возможно я чего то не понимаю.
А зачем insert into через EvalBuf Почему не использовали RecordInsertList Он должен оптимальнее работать. Заодно можно через common работать с любым типом буфера. |
|
13.07.2017, 17:54 | #14 |
Участник
|
Цитата:
Сообщение от 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),...); Спасибо, попробую! |
|
13.07.2017, 17:57 | #15 |
Участник
|
Ещё "чайник" в Аксапте. Поэтому приветствуются любые решения. EvalBuf вообще не работает с переменными, только с выражениями. Завтра "покурю" Ваш совет по мануалам.
|
|
13.07.2017, 18:01 | #16 |
Участник
|
|
|
|
За это сообщение автора поблагодарили: AfterEarth (1). |
13.07.2017, 18:58 | #17 |
Banned
|
Цитата:
Сообщение от AfterEarth
Есть задача - сделать запрос с динамическими данными -выбирать значения из переменных для insert в зависимости от описания и имён полей, а также переменных по имени из таблицы.
Это выгрузки в различные форматы, чтобы не писать на каждую выгрузку свою функцию. ... Уже "наколбашено" штук 15 и ещё 15 нужно, а потом будут ещё. Смысле копипаст делать? Не по программистки это :-/ Если вы же профессионал, то за такое программирование надо бить, а потом еще раз бить. Это программизм небитого энтузиаста, а не программирование. Если есть общее - выделите в родительский класс, если нет сделайте как набор статических методов. Пусть их будет 50 методов или 50 классов - вам всем скажут только спасибо, а не будут проклинать. |
|
|
За это сообщение автора поблагодарили: ta_and (4). |
13.07.2017, 19:22 | #18 |
Участник
|
Абсолютно согласен.
Извращаться для себя чисто в образовательном плане можно сколько угодно. Но если это делать в рабочем приложении... то это жесть. Попробуйте сделать нормальную постановку задачи и тогда будет видно грамотное архитектурное решение без всяких чесаний инсертов через ранбуф. Последний раз редактировалось ta_and; 13.07.2017 в 19:24. |
|
|
За это сообщение автора поблагодарили: ax_mct (5). |
13.07.2017, 20:35 | #19 |
Участник
|
Поскольку не очень понятно, что вы пытаетесь сделать, опубликуйте здесь часть вашего кода. А мы подправим, или направим на путь истинный.
P.S. Посмотрите также в сторону AIF. Об этом можно почитать в книге "MS Dynamics AX 4.0 Справочник профессионала".
__________________
// no comments |
|
17.07.2017, 12:18 | #20 |
Участник
|
Цитата:
Сообщение от ax_mct
Если вы сидите на клиенте как постоянный программист и просто от скуки извращаетесь, то конечно можно все.
Если вы же профессионал, то за такое программирование надо бить, а потом еще раз бить. Это программизм небитого энтузиаста, а не программирование. Если есть общее - выделите в родительский класс, если нет сделайте как набор статических методов. Пусть их будет 50 методов или 50 классов - вам всем скажут только спасибо, а не будут проклинать. |
|
|
|