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

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 06.08.2008, 18:24   #1  
Hub is offline
Hub
Участник
 
51 / 10 (1) +
Регистрация: 20.05.2008
MAP vs Class. В чем идейная необходимость в MAP-ах? А что если использовать Class вместо MAP?
MAP vs Class. В чем идейная необходимость в MAP-ах? А что если использовать Class вместо MAP?
Старый 06.08.2008, 19:48   #2  
glibs is offline
glibs
Member
Сотрудники компании It Box
Most Valuable Professional
Лучший по профессии 2011
Лучший по профессии 2009
 
4,942 / 911 (40) +++++++
Регистрация: 10.06.2002
Адрес: I am from Kyiv, Ukraine. Now I am in Moscow. For private contacts: glibs@hotmail.com
А как вы в класс будете передавать буфер различных таблиц и там его обрабатывать?
__________________
С уважением,
glibs®
Старый 07.08.2008, 09:51   #3  
MikeR is offline
MikeR
MCT
Аватар для MikeR
MCBMSS
Лучший по профессии 2015
Лучший по профессии 2014
 
1,628 / 627 (24) +++++++
Регистрация: 28.11.2005
Адрес: просто землянин
Стот отметить, что Map в Axapt-e реализован как две сущности. Одна это класс коллекции, а другая это сущность в АОТ. Одна служит для обработки объектов в оперативной памяти, а вторая для удобства заполнения сущностей с одинаковым набором полей как то Поставщики-Клиенты.
Класс - это некая структура (базовый кирпичик) для постоения модификаций.
Если сравнивать первый Map и class, то здесь есть особенности того, что в мапе присуствует ключ и его можно использовать как некий упорядочный список. Он удобен для кэширования информации.
Множественные ключи в нем могут прикрепляться к одному и тому же значению, но один ключ может прикрепляться только к одному значению за раз. Добавление пары ключа и значения в место, где ключ уже привязан к значению изменит связь так, что ключ будет привязан к новому значению.
X++:
Map map = new Map(Types::String, Types::Enum);
Word wordType;
;
map.insert("Car", Word::Noun);
map.insert("Bike", Word::Noun);
map.insert("Walk", Word::Verb);
map.insert("Nice", Word::Adjective);

print map.elements(); //4;

wordType = map.lookup("Car");
print strfmt("Car is a %1", wordType); //Car is a Noun
pause;
Старый 07.08.2008, 10:00   #4  
Raven Melancholic is offline
Raven Melancholic
Участник
Аватар для Raven Melancholic
Самостоятельные клиенты AX
Лучший по профессии 2015
 
2,164 / 1293 (48) ++++++++
Регистрация: 21.03.2005
Адрес: Москва-Петушки
Цитата:
Сообщение от glibs Посмотреть сообщение
А как вы в класс будете передавать буфер различных таблиц и там его обрабатывать?
Ну, примерно так, как это реализовано в InventMovement и наследниках.
Старый 07.08.2008, 11:28   #5  
kashperuk is offline
kashperuk
Участник
Аватар для kashperuk
MCBMSS
Соотечественники
Сотрудники Microsoft Dynamics
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии 2011
Лучший по профессии 2009
 
4,361 / 2084 (78) +++++++++
Регистрация: 30.05.2004
Адрес: Atlanta, GA, USA
По сути, Map - это тоже класс, реализовывающий экземпляр hash table в АХ.
То есть вместо того, чтобы писать свой класс, который будет делать то же самое, что и мап, можно использовать уже написанный.
Более того, так как это кернел класс, он будет работать намного быстрее Вашего application level класса.
Старый 07.08.2008, 12:53   #6  
glibs is offline
glibs
Member
Сотрудники компании It Box
Most Valuable Professional
Лучший по профессии 2011
Лучший по профессии 2009
 
4,942 / 911 (40) +++++++
Регистрация: 10.06.2002
Адрес: I am from Kyiv, Ukraine. Now I am in Moscow. For private contacts: glibs@hotmail.com
Цитата:
Сообщение от Raven Melancholic
...Ну...
Ну если вам так нравится кодить шедевры... да и еще вы это делаете без ошибок... и никому потом с этим не придется разбираться... и вам не жалко времени... и вы получаете от этого удовольствие... то, конечно, можно.
__________________
С уважением,
glibs®
Старый 07.08.2008, 13:58   #7  
Hub is offline
Hub
Участник
 
51 / 10 (1) +
Регистрация: 20.05.2008
Всем спасибо! В общем понятно.

Цитата:
Сообщение от kashperuk Посмотреть сообщение
По сути, Map - это тоже класс, реализовывающий экземпляр hash table в АХ.
(Чешу затылок) Что это?

Цитата:
Сообщение от kashperuk Посмотреть сообщение
Более того, так как это кернел класс, он будет работать намного быстрее Вашего application level класса.
Это относится к именно элементу MAP, а не к системному классу Map?
Старый 07.08.2008, 14:15   #8  
kashperuk is offline
kashperuk
Участник
Аватар для kashperuk
MCBMSS
Соотечественники
Сотрудники Microsoft Dynamics
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии 2011
Лучший по профессии 2009
 
4,361 / 2084 (78) +++++++++
Регистрация: 30.05.2004
Адрес: Atlanta, GA, USA
Цитата:
Сообщение от Hub Посмотреть сообщение
(Чешу затылок) Что это?
http://en.wikipedia.org/wiki/Hash_table

Цитата:
Сообщение от Hub Посмотреть сообщение
Это относится к именно элементу MAP, а не к системному классу Map?
Это относится к системному (kernel) классу Map. То, что он системный, значит, что его код написан на C++, а не на Х++. А это существенно ускоряет его работу
Старый 07.08.2008, 14:31   #9  
Hub is offline
Hub
Участник
 
51 / 10 (1) +
Регистрация: 20.05.2008
Цитата:
Сообщение от kashperuk Посмотреть сообщение
Хэш таблицы, функции - известное дело. А в контексте выражения "Map - это тоже класс, реализовывающий экземпляр hash table в АХ" - это непонятно.
Старый 07.08.2008, 14:34   #10  
kashperuk is offline
kashperuk
Участник
Аватар для kashperuk
MCBMSS
Соотечественники
Сотрудники Microsoft Dynamics
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии 2011
Лучший по профессии 2009
 
4,361 / 2084 (78) +++++++++
Регистрация: 30.05.2004
Адрес: Atlanta, GA, USA
Поправочка (спасибо mbelugin)
Map реализован как C++ container:
http://en.wikipedia.org/wiki/Map_(C%2B%2B_container)
Старый 07.08.2008, 14:47   #11  
sukhanchik is offline
sukhanchik
Administrator
Аватар для sukhanchik
MCBMSS
Злыдни
Лучший по профессии 2015
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
3,309 / 3546 (125) ++++++++++
Регистрация: 13.06.2004
Адрес: Москва
2 Hub: Вы таки спрашиваете про элемент MAP ?
Если про элемент - то могу сказать, зачем они нужны. Представьте себе 2 или более таблиц, которые "похожи" по структуре, но в реалии отличаются. К примеру - клиенты, поставщики, сотрудники.... Представьте теперь, что элемент MAP - является своего рода базовым классом над этими таблицами. Т.е. туда можно свалить общий для всех таблиц код. Разница между обычными классами и связкой MAP-Таблица состоит в том, что при разработке - сначала делается базовый класс, а потом его потомки. А тут наоборот. Сначала - таблицы - а потом базовый класс как бы "собирается". При этом, т.к. формально наследования нет - то формально можно создать много MAPов на один и тот же набор таблиц. Только это лишено логического смысла.
Вот вкратце описание - для чего нужен элемент MAP
__________________
Возможно сделать все. Вопрос времени
Старый 07.08.2008, 14:53   #12  
MikeR is offline
MikeR
MCT
Аватар для MikeR
MCBMSS
Лучший по профессии 2015
Лучший по профессии 2014
 
1,628 / 627 (24) +++++++
Регистрация: 28.11.2005
Адрес: просто землянин
Цитата:
Сообщение от kashperuk Посмотреть сообщение
Поправочка (спасибо mbelugin)
Map реализован как C++ container:
http://en.wikipedia.org/wiki/Map_(C%2B%2B_container)
Хм прикольно.
То есть что то типа этого?
X++:
#include <iostream>
#include <map>
using namespace std;
 
int main()
{
        typedef map<char, int> mapType;
        mapType myMap;
 
        // insert elements using insert function
        myMap.insert(pair<char, int>('a', 1));
        myMap.insert(pair<char, int>('b', 2));
        myMap.insert(pair<char, int>('c', 3));
        myMap.insert(pair<char, int>('d', 4));
        myMap.insert(pair<char, int>('e', 5));
 
        // erase the first element using the erase function
        mapType::iterator iter = myMap.begin();
        myMap.erase(iter);
 
        // output the size of the map
        cout << "Size of myMap: " << myMap.size() << endl;
 
        cout << "Enter a key to search for: ";
        char c;
        cin >> c;
 
        // find will return an iterator to the matching element if it is found
        // or to the end of the map if the key is not found
        iter = myMap.find(c);
        if( iter != myMap.end() ) 
                cout << "Value is: " << iter->second << endl;
        else
                cout << "Key is not in myMap" << endl;
 
        // clear the entries in the map
        myMap.clear();
}
Старый 07.08.2008, 15:33   #13  
Hub is offline
Hub
Участник
 
51 / 10 (1) +
Регистрация: 20.05.2008
Цитата:
Сообщение от sukhanchik Посмотреть сообщение
2 Hub: Вы таки спрашиваете про элемент MAP ?
Если про элемент - то могу сказать, зачем они нужны. Представьте себе 2 или более таблиц, которые "похожи" по структуре, но в реалии отличаются. К примеру - клиенты, поставщики, сотрудники.... Представьте теперь, что элемент MAP - является своего рода базовым классом над этими таблицами. Т.е. туда можно свалить общий для всех таблиц код. Разница между обычными классами и связкой MAP-Таблица состоит в том, что при разработке - сначала делается базовый класс, а потом его потомки. А тут наоборот. Сначала - таблицы - а потом базовый класс как бы "собирается". При этом, т.к. формально наследования нет - то формально можно создать много MAPов на один и тот же набор таблиц. Только это лишено логического смысла.
Вот вкратце описание - для чего нужен элемент MAP
Бррр... MAP - это обертка элемента Таблица. В данном случае имеет место быть ad hoc наследование.
Старый 08.08.2008, 09:58   #14  
Raven Melancholic is offline
Raven Melancholic
Участник
Аватар для Raven Melancholic
Самостоятельные клиенты AX
Лучший по профессии 2015
 
2,164 / 1293 (48) ++++++++
Регистрация: 21.03.2005
Адрес: Москва-Петушки
Цитата:
Сообщение от glibs Посмотреть сообщение
кодить шедевры...
Спасибо за комплимент но. к сожалению, не могу ни принять на свой счёт, ни вписать в резюме, так как автором иерархии классов, в основе которых лежит InventMovement я не являюсь.
Цитата:
Сообщение от glibs Посмотреть сообщение
да и еще вы это делаете без ошибок
В использовании классов, наследников InventMovement есть ошибки, но внёс их не я.
Цитата:
Сообщение от glibs Посмотреть сообщение
и никому потом с этим не придется разбираться
Есть документальные подтверждения, что как минимум один человек разбирался с классами из иерархии InventMovement (в инете есть статья от Fed), поэтому обобщение никому не подходит.
Цитата:
Сообщение от glibs Посмотреть сообщение
вам не жалко времени
Время очень жалко - этот ресурс невосполнимый. Но время, затраченное на разбор вызова, подобному:
X++:
movement = InventMovement::construct(salesLine, InventMovSubType::None, _childBuffer)
estimated = InventUpd_Estimated::newInventMovement(movement);
estimated.updateNow();
у меня уходит меньше, чем на перепрыгивание из:
X++:
this.LineAmount  = this.lineAmountMST(this.Qty);
где this это совсем оказывается не this, а ссылка на строку таблицы. Из метода последней вытягивается красивым синтаксисом другой map:
X++:
this.SalesPurchLine::lineAmountMST
Повторюсь, на перепрыгивание туда-сюда мне времени жалко, причем, в this.lineAmountMST(this.Qty) стандартная функция просмотра определения не работает (понятно почему).
Еще мне жалко времени на то, что при загрузке проектов, полученных от аутсорсеров при наличии в них изменённых мапов я не могу выполнить сравнение из-за застарелой ошибки сравнения ветки Mappings.
Так что времени мне действительно жалко, поэтому предпочитаю, если есть возможность использовать не мапы, а классы.
Старый 08.08.2008, 11:57   #15  
avf is offline
avf
Участник
 
31 / 24 (1) +++
Регистрация: 28.06.2007
Цитата:
Сообщение от Inside MS DAX;
Maps (Data Association Model Elements) provide a useful common interface to data entities and prevent the need to duplicate methods on denormalized tables, but you should use maps only when normalization is not an option.
Цитата:
Сообщение от Raven Melancholic;
где this это совсем оказывается не this, а ссылка на строку таблицы. Из метода последней вытягивается красивым синтаксисом другой map....
Так что времени мне действительно жалко, поэтому предпочитаю, если есть возможность использовать не мапы, а классы.
Угу, синтаксис удался) Согласен, для выноса общей функциональности приятнее использовать классы. А вот с задачей создания единообразного интерфейса к полям денормализованных таблиц Map-ы справляется на ура.

Последний раз редактировалось avf; 08.08.2008 в 11:59.
Старый 08.08.2008, 11:59   #16  
Bishop is offline
Bishop
Участник
 
89 / 60 (3) ++++
Регистрация: 12.08.2004
Адрес: Москва
Цитата:
Сообщение от Raven Melancholic Посмотреть сообщение
Повторюсь, на перепрыгивание туда-сюда мне времени жалко, причем, в this.lineAmountMST(this.Qty) стандартная функция просмотра определения не работает (понятно почему).
Еще мне жалко времени на то, что при загрузке проектов, полученных от аутсорсеров при наличии в них изменённых мапов я не могу выполнить сравнение из-за застарелой ошибки сравнения ветки Mappings.
Так что времени мне действительно жалко, поэтому предпочитаю, если есть возможность использовать не мапы, а классы.
Наверное, надо исходить от задачи. Одно дело - обобщить три пары полей в двух таблицах, другое - реализовать общие механизмы типа журнализации, работы с адресами и т.д.
Так что здесь на одной чаше весов - удобное "перепрыгивание", а на другой:
- быстродействие (мэппинг - это все таки "ядро", и этим НАДО пользоваться),
- простота (трудозатраты на создание, расширение и поддержку мэппинга классами существенно больше),
- шаблон (разработчики, как художники, непременно реализуют конкретный мэппинг каждый по-своему)

Поэтому, я голосую за MAP (хотя, по чесноку, чаще пишу классы ).
А "перепрыгивание" еще много где не работает (или работает не так как хотелось бы). В тех же классах из метода базового класса уже не "перепрыгнуть" в наследника, и все-равно приходится активно работать с репозитарием.

Да, и еще, InventMovement и Ко я бы не стал относить к попытке реализации мэппинга, все-таки это InventMovement...
Старый 11.08.2008, 16:58   #17  
kashperuk is offline
kashperuk
Участник
Аватар для kashperuk
MCBMSS
Соотечественники
Сотрудники Microsoft Dynamics
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии 2011
Лучший по профессии 2009
 
4,361 / 2084 (78) +++++++++
Регистрация: 30.05.2004
Адрес: Atlanta, GA, USA
Я тут ухватился за
Цитата:
Сообщение от Bishop
В тех же классах из метода базового класса уже не "перепрыгнуть" в наследника, и все-равно приходится активно работать с репозитарием.
, написал 2 варианта перехода к перекрытому методу наследника текущего класса.

Скорость работы обоих специально не сравнивал. Она зависит от результата выборки. На глаз не могу выбрать один либо второй
Кому интересно, посмотрите проект, было бы интересно, если бы кто-то замерил время.
Первый раз и там и там, ессно, выполняется долго довольно.

Через Dictionary
X++:
public void addIns_OpenOverriddenMethodDef(Editor e)
{
    #AOT
    #define.AOTDelimiter('\\') // This does not exist in AX versions prior to AX 2009, so I just declare it here
    TreeNode        treeNode = TreeNode::findNode(e.path());
    TreeNode        treeNodeParent;
    Dictionary      dictionary = new Dictionary();
    Counter         classCnt = dictionary.classCnt();
    Counter         iClassCount;
    ClassId         classIdParent;
    ClassId         classIdChild;
    Counter         descendentsCount;
    SysDictClass    dictClassChild;
    TreeNodeName    methodName = treeNode.treeNodeName();
    Map             map;
    MapEnumerator   mapEnumerator;
    ;
    if (subStr(treeNode.treeNodePath(), 1, strLen(#ClassesPath)) == #ClassesPath)
    {
        treeNodeParent = TreeNode::findNode(xUtilElements::getNodePathRough(xUtilElements::parentElement(xUtilElements::findTreeNode(treeNode))));
        classIdParent = dictionary.className2Id(treeNodeParent.treeNodeName());
        map = new Map(Types::String, Types::String);
        for (iClassCount = 1; iClassCount <= classCnt; iClassCount++)
        {
            classIdChild = dictionary.classCnt2Id(iClassCount);
            if (SysDictClass::isSuperclass(classIdChild, classIdParent))
            {
                descendentsCount++;
                treeNode = TreeNode::findNode(#ClassesPath + #AOTDelimiter + classId2Name(classIdChild) + #AOTDelimiter + methodName);
                if (treeNode)
                {
                    map.insert(treeNode.treeNodePath(), treeNode.AOTparent().treeNodeName());
                }
            }
        }
        switch (map.elements())
        {
            case 0:
                info(strFmt("The method '%1' is not overridden in any of the %2 descendent classes", methodName, descendentsCount));
                break;
            case 1:
                mapEnumerator = map.getEnumerator();
                if (mapEnumerator.moveNext())
                    treeNode = TreeNode::findNode(mapEnumerator.currentKey());
                else
                    error("Internal error. map.elements() == 1, but mapEnumerator did not find it");
                break;
            default:
                treeNode = TreeNode::findNode(pickList(map, "Method definition", "Pick required class to go to method definition"));
        }
        if (treeNode && SysTreeNode::hasSource(treeNode))
            treeNode.AOTedit();
    }
}
Через xRef
X++:
public void addIns_OpenOverriddenMethodDefXRef(Editor e)
{
    #define.AOTDelimiter('\\')
    #AOT
    TreeNode        treeNode = TreeNode::findNode(e.path());
    TreeNode        treeNodeParent;
    ClassId         classIdParent;
    TreeNodeName    methodName = treeNode.treeNodeName();
    Map             descendents;
    MapEnumerator   descendentsEnumerator;
    Counter         descendentsCount;

    void findDescendents(ClassId _parentId)
    {
        xRefTypeHierarchy   typeHierarchy;
        TreeNode            descendent;
        ;
        while select typeHierarchy
            where typeHierarchy.Parent == _parentId &&
                  typeHierarchy.BaseType == Types::Class

        {
            descendentsCount++;
            descendent = TreeNode::findNode(#ClassesPath + #AOTDelimiter + typeHierarchy.Name + #AOTDelimiter + methodName);
            if (descendent)
                descendents.insert(descendent.treeNodePath(), descendent.AOTparent().treeNodeName());

            if (typeHierarchy.Children && typeHierarchy.Id)
                findDescendents(typeHierarchy.Id);
        }
    }
    ;
    if (subStr(treeNode.treeNodePath(), 1, strLen(#ClassesPath)) == #ClassesPath)
    {
        treeNodeParent = TreeNode::findNode(xUtilElements::getNodePathRough(xUtilElements::parentElement(xUtilElements::findTreeNode(treeNode))));
        classIdParent = className2Id(treeNodeParent.treeNodeName());
        descendents = new Map(Types::String, Types::String);
        if (xRefTypeHierarchy::findOrCreate(Types::Class, classIdParent).Children)
            findDescendents(classIdParent);

        switch (descendents.elements())
        {
            case 0:
                info(strFmt(@"The method '%1' is not overridden in any of the %2 descendent classes", methodName, descendentsCount));
                break;
            case 1:
                descendentsEnumerator = descendents.getEnumerator();
                if (descendentsEnumerator.moveNext())
                    treeNode = TreeNode::findNode(descendentsEnumerator.currentKey());
                break;
            default:
                treeNode = TreeNode::findNode(pickList(descendents, "@SYS24724", @"Pick required class to go to method definition"));
        }
        if (treeNode && SysTreeNode::hasSource(treeNode))
            treeNode.AOTedit();
    }
}
Собственно - хотелось бы получить комментарии, замечания и пожелания
Спасибо

Последний раз редактировалось kashperuk; 12.08.2008 в 10:36. Причина: Немного улучшил производительность xRef версии
За это сообщение автора поблагодарили: aidsua (1), alex55 (1).
 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
Denis Fedotenko: Себестоимость и закрытие склада Blog bot DAX: База знаний и проекты 44 29.03.2010 14:54
Kashperuk Ivan: List panels in Dynaics AX - a short description of SysListPanel class Blog bot DAX Blogs 1 21.10.2007 22:51
Kashperuk Ivan: Description of ClassBuild class:Today I want to ... Blog bot DAX Blogs 0 26.01.2007 05:51
Говорят вышел SP2 для Axapta 3. Кто нибуть что знает на эту тему? soin DAX: Прочие вопросы 10 13.10.2003 10:43

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

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

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