![]() |
#1 |
Участник
|
В чем смысл подобной конструкции?
Я щас глупость спрошу. Но весь мозг сломал в размышлениях "зачем?"
AX2012 R3. Класс RetailCDXChannelSpecificData, метод trackChannelDBAssignment() вот очищенный от лишнего код: X++: public void trackChannelDBAssignment() { container channelDB; int i; RefRecId channelDBRecId; while select RefRecId from ref1 where // условия { channelDB += ref1.RefRecID; } for (i = 1; i <= conLen(channelDB); ++i) { channelDBRecId = conPeek(channelDB, i); // некие действия } } нафига разработчики Майкрософт сначала собирают контейнер, а затем делают цикл по контейнеру? контейнер - внутренняя переменная, никуда не возвращается, никаких побочных эффектов он не дает. никаких действий со счетчиком не выполняется. счетчик не возвращается. break'ов из циклов тоже не бывает. ЗАЧЕМ? Почему не сразу один цикл? X++: public void trackChannelDBAssignment() { RefRecId channelDBRecId; while select RefRecId from ref1 where // условия { channelDBRecId = ref1.RefRecID; // некие действия } } |
|
![]() |
#2 |
Участник
|
Может для того чтобы меньше блокировать таблицу ref1. Побыстрее "отпустить". Если операции вставка/удаление/изменение записей в этой таблице происходят часто, а "некие действия" достаточно продолжительны, то вполне возможно - это такая оптимизация.
Последний раз редактировалось S.Kuskov; 29.07.2014 в 12:22. |
|
![]() |
#3 |
Участник
|
Цитата:
никаких особо длинных операций не выполняется. вот полный код: X++: /// <summary> /// Tracks channel database assignment. /// </summary> public void trackChannelDBAssignment() { container channelDB; int i; RefRecId channelDBRecId; RefRecId channelRecId; RetailCDXDataStoreChannel dataStoreChannel; while select RefRecId from ref1 where ref1.NodeID == 0 && ref1.RefTableID == tableNum(RetailCDXDataStoreChannel) && ref1.SYS_CHANGE_OPERATION == 'I' { channelDB += ref1.RefRecID; } for (i = 1; i <= conLen(channelDB); ++i) { channelDBRecId = conPeek(channelDB, i); select Channel from dataStoreChannel where dataStoreChannel.RecId == channelDBRecId; channelRecId = dataStoreChannel.Channel; select firstOnly RecId from ref1 where ref1.NodeID == 0 && ref1.RefTableID == tableNum(RetailChannelTable) && ref1.SYS_CHANGE_OPERATION == 'I' && ref1.RefRecID == channelRecId; if (!ref1) { ref1.initValue(); ref1.NodeID = 0; ref1.RefTableID = tableNum(RetailChannelTable); ref1.RefRecID = channelRecId; ref1.SYS_CHANGE_OPERATION = 'I'; ref1.insert(); } } } но даже предположить не могу ЗАЧЕМ? |
|
![]() |
#4 |
Участник
|
Ну так они же во втором цикле вносят изменения в данные влияющие на выборку в первом.
UPD.: Хотя нет, показалось. Там RefTableID другой. Ну может быть им так же как и мне показалось Последний раз редактировалось S.Kuskov; 29.07.2014 в 12:34. |
|
![]() |
#5 |
Участник
|
Цитата:
![]() не совсем так, в условии выборки присуствует tablenum одной таблицы, а вставляют они tablenum другой таблицы. поэтому выборку они не меняют. если бы это был программист на каком-нибудь проекте, я бы подумал, что он не умеет объявлять еще одну локальную табличную переменную вместо повторного использования ref1... подумал бы... и уволил программиста нафиг. но здесь вроде майкрософтовский код... и может быть, я чего не знаю? |
|
![]() |
#6 |
Участник
|
покопал на предмет использования побочных эффектов с ref1.
ref1 определен как переменная класса. но не, ref1 после вызова не используется. побочных эффектов нет. ЗАЧЕМ? |
|
![]() |
#7 |
Участник
|
А метод ref1.insert() не перекрыт? Там ничего существенного не происходит?
|
|
![]() |
#8 |
Участник
|
Цитата:
эта таблица временная. спасибо за направление. сюда несомненно стоит подумать. но ведь ничто не мешает объявить локальную переменную и направить ее на тот же набор временных записей, что и переменная класса ref1. или таки нет? |
|
![]() |
#9 |
Moderator
|
Цитата:
Сообщение от mazzy
![]() ![]() не совсем так, в условии выборки присуствует tablenum одной таблицы, а вставляют они tablenum другой таблицы. поэтому выборку они не меняют. если бы это был программист на каком-нибудь проекте, я бы подумал, что он не умеет объявлять еще одну локальную табличную переменную вместо повторного использования ref1... подумал бы... и уволил программиста нафиг. но здесь вроде майкрософтовский код... и может быть, я чего не знаю? Конечно там insert_recordset напрашивается... |
|
![]() |
#10 |
Участник
|
Цитата:
это код из R3. это код, который наваяли уже в Майкрософте весной этого года. унаследованный был в r2 раньше. в унаследованном порядка и логичности было больше. Хотя и там были места для рефакторинга. Но хоть какое-то логичное объяснение тогдашнему коду было. |
|
![]() |
#11 |
Участник
|
Таки да, очень похоже на то что они не знали о такой возможности SetTmpData. Других объяснений у меня больше нет
Последний раз редактировалось S.Kuskov; 29.07.2014 в 12:53. |
|
![]() |
#12 |
Участник
|
Такую конструкцию не только заморские программисты пишут, часто встречал при кодревью, но на вопрос "зачем?" так никто и не ответил, просто переделывали под второй вариант. видимо зашито где-то в подсознании
![]() |
|
![]() |
#13 |
Участник
|
Делал такое иногда в оракле для длительных процедур.
Например делаем перебор номенклатурного справочника, а для каждой номенклатуры выполняется какая-о длительная операция. Если перебор номенлктаур делать в цикле как предлагал Маззи, то может вылезти ошибка "Snapshot is too old" или что-то в этом духе. В общем сегмент повтора пришлось бы увеличить чтобы этого не было. Для обхода такой особенности, обычно быстро начитывали перечень интересующих номенклатур в set, освобождали курсор и спокойно работали дальше начитывая номенклатуры из Set-а (контейнер - это кривизна !) Возможно для SQL сервера тоже бывают аналогичные проблемы. Версионность забесплатно не дается. На неё БД все равно тратит ресурсы. |
|
![]() |
#14 |
Moderator
|
А что ты поповоду использования контейнера думаешь ? Он же immutable - каждый раз память захватывается и освобождается. По моему - правильнее было бы set использовать. (Даже если есть какой-то смысл в подходе в целом). Ну то есть - на мой взгляд - вероятность просто кривого программирования намного выше, чем вероятность хитрого подхода...
|
|
|
За это сообщение автора поблагодарили: mazzy (2), S.Kuskov (1). |
![]() |
#15 |
Участник
|
грустно, девушки...
![]() ключевое слово - "длительных". для длительных я согласен, наверное. хотя все равно лучше объявить вторую переменную по методу из книжки Еременко. но в данном то случае никаких "длительных" нет. и не предполагается. вся байда в пределах одного метода. ================== смотрю я на код retail'а в R3, хочется шипя материться. такого накала идиотии давно не видел. все таки остается надежда, что я чего то не понимаю. |
|
![]() |
#16 |
Участник
|
Цитата:
Однако на .net короткоживущие переменные - очень даже хорошо. сборщик мусора в .net как раз лучше справляется с переменными, которые живут недолго - одно-два поколения. долгоживущие переменные в .net уходят в специальную очередь и обслуживаются специальными алгоритмами сборщика мусора. предполагается, что данный код будет исполняться в пакетном режиме и в CIL. поэтому бог с ними, с контейнерами. мне непонятно зачем надо было городить ТАКОЙ огород с двумя циклами. при условии, что нет никаких длительных операций. Цитата:
Виктор поразился, какое лицо сделалось у Дианы. Как на картине. Даже не на картине – на иконе. Странная неподвижность черт, и ты недоумеваешь, то ли это замысел мастера, то ли бессилие ремесленника.
|
|