17.10.2018, 15:37 | #1 |
Участник
|
Паттерн Related Table
Решил немного порязмять свои писательские способности и черканул в блоге об использовании простенького паттерна.
Вот ссылка. Говорится о том, как хорошо было бы стандартизовать табличные методы, возвращающие ссылки на связанные таблицы. И да, если мы это будем использовать только локально, проку будет мало. Однако (не знаю, как там сейчас дела обстоят в D365) если Microsoft возьмет на вооружение, то это было бы очень существенно. Вообще у кого какие мысли по данному паттерну? Интересно или бесполезно?
__________________
// no comments Последний раз редактировалось dech; 17.10.2018 в 16:08. |
|
|
За это сообщение автора поблагодарили: trud (2), wojzeh (1). |
17.10.2018, 15:58 | #2 |
Участник
|
Лучше в ссылку добавить https
__________________
Ivanhoe as is.. |
|
17.10.2018, 16:10 | #3 |
Участник
|
__________________
// no comments |
|
17.10.2018, 16:59 | #4 |
Участник
|
чем только люди в Омске не развлекаются!
теперь по делу. 1. не понял, где будем обсуждать - тут или там, где сама статья (по умолчанию буду тут) 2. "Пожалуй уже всем надоело каждый раз выискивать подходящий метод" - не в том дело, что надоело, а в том, что его иногда просто нет. это ж вопрос воспитания: добавил рилейшон - добавь метод! 3. если интересует настоящая расширяемость, когда код пишется один раз, а дальше хоть трава не расти, то вот мои reflections по этому поводу: X++: static void wzhGetRelatedTableNames(Args _args) { wblInExtCodeValueTable wblInExtCodeValueTable; int mapId; TableName relatedTableName; TableId relatedTableId; Set tablesIdsSet = new Set(Types::Integer); Set tablesNamesSet = new Set(Types::String); TableId tableId = tableName2id(tableStr(wblInExtCodeValueTable)); Dictionary dictionary = new Dictionary(); SysDictTable dictTable = dictionary.tableObject(tableId); DictRelation dictRelation = new DictRelation(wblInExtCodeValueTable.TableId); int mapCnt = dictTable.relationCnt(); container ret ; str relationName; //create a maps of literals for all tables from the table relations // so that we could get tables names based on their ids // and if any new relation will be added to multiple external codes table // it is present automatically in this view for (mapId=1; mapId <= mapCnt; mapId++) { // elaborate if any table present many times relationName = dictTable.relation(mapId); dictRelation.loadNameRelation(relationName); if(dictRelation) { relatedTableId = dictRelation.externTable(); relatedTableName = tableId2pname(relatedTableId); tablesIdsSet.add(relatedTableId); tablesNamesSet.add(relatedTableName); info(strFmt("Table %1 - %2", relatedTableId, relatedTableName)); } } ret = [tablesIdsSet.pack(), tablesNamesSet.pack()]; } я сделал через table map связь внешних кодов 1:N
__________________
Felix nihil admirari |
|
|
За это сообщение автора поблагодарили: dech (5). |
17.10.2018, 17:28 | #5 |
Участник
|
|
|
|
За это сообщение автора поблагодарили: wojzeh (1), S.Kuskov (5), dech (3). |
17.10.2018, 17:48 | #6 |
Участник
|
|
|
17.10.2018, 17:52 | #7 |
Участник
|
а какие там "подводные камни" у этого подхода? там, в каментах, народ жалуется, дескать, что-то не так работает.
я как-то раз пользовался этой штукой, по-моему, когда создавал кучу связанных записей с помощью unitOfWork и чтоб два раза не вставать: это только у меня не работает Set tableRelationsSet = DictTable.relations() ?
__________________
Felix nihil admirari |
|
17.10.2018, 18:13 | #8 |
Administrator
|
Изначальная мысль интересная. Но я бы все-таки ее привязывал к релейшнам, как это сделано в AX2012 (ссылку дал belugin). Это более правильно на мой взгляд (и кстати в 2012 работает).
Но в D365: 1. Подход из AX2012 не работает (ну или я с этим не разобрался) 2. Принципиально реализован другой подход к разработке. В частности - чаще используются сложные запросы, вьюхи, готовые классы, инкапсулирующие внутри себя все потребности составления запросов. 3. Появились расширения, в результате которых код и релейшны одной таблицы могут быть разбросаны по многим расширениям и многим классам. Т.е. найти этот "related" метод будет весьма сложно. А порой и невозможно, если нет ссылок на модель, в которой он присутствует. Поэтому я бы эту мысль классифицировал, как мысль, у которой нет хорошего решения по реализации. В 2009 и ранее - используется один подход, в 2012 - другой, а в D365 - третий.
__________________
Возможно сделать все. Вопрос времени |
|
17.10.2018, 18:17 | #9 |
Участник
|
его идея как раз в том, чтоб не привязываться к синтаксису (имени метода) при поиске связанной записи. вьюхи-шмухи тут ни при чём.
__________________
Felix nihil admirari |
|
17.10.2018, 18:49 | #10 |
Administrator
|
Цитата:
В 2012 и далее многие таблицы "распилили", т.о., к примеру, чтобы перейти от inventTrans к custTable / vendTable нужно еще "прыгнуть" в inventTransOrigin и оттуда - в DirPartyTable. Но поскольку исходная задача не изменилась (т.е. сама inventTransOrigin никому особо не нужна - нужен в конечном счете только клиент), то и потребности в переходе к отдельно взятой промежуточной таблице, которая появилась исключительно по техническим причинам - нет. Т.е. теперь, если захочется перейти от inventTrans к custTable - нужно будет написать некий кверик с джойнами из нескольких таблиц (=вьюха), либо ... найти комбинацию штатных методов, которая в конечном счете приведет к требуемому результату. Про LedgerTrans я уж вообще молчу - там 5 таблиц целых . А для тех же финаналитик сделаны готовые классы, которые успешно работают и которые вполне можно применять, вообще не заморачиваясь на внутреннюю реализацию структуры финаналитик и не делая ни одного джойна (а джойны, если их делать - там тоже получатся многоэтажные). Поэтому и потребность в переходе от одной таблице к другой одним методом, как это было раньше через find по сути - сильно уменьшилась и осталась только для менее востребованных таблиц
__________________
Возможно сделать все. Вопрос времени |
|
17.10.2018, 19:10 | #11 |
Участник
|
похоже, вы с ним о разных вещах говорите:
"табличные методы, возвращающие ссылки на связанные таблицы" - то есть, как получить то, что у нас есть. в приведённой тобой таблице inventTrans нет таких связанных таблиц, как CustTable, VendTable, но есть, например Currency и ProjTable. то есть, как добраться до того, чего у нас тут на таблице нет.
__________________
Felix nihil admirari |
|
17.10.2018, 19:36 | #12 |
Administrator
|
Не совсем. Топикстартер предлагает решение некой задачи и предлагает его обсудить. Я же говорю о том, что в силу изменившейся архитектуры системы в последних версиях системы исходная задача становится маловостребованной и поэтому предлагаемое решение имеет ограничение по своему применению
__________________
Возможно сделать все. Вопрос времени |
|
17.10.2018, 19:39 | #13 |
Участник
|
приведи пример, где предлагаемое им решение не сработает в связи с "изменившейся архитектурой".
ты, кстати говоря, видел, как у меня открываются формы по ссылке на разные таблицы?
__________________
Felix nihil admirari |
|
18.10.2018, 00:11 | #14 |
Administrator
|
Цитата:
Нет. Ну да - в этом случае тот вариант метода конечно незаменим.
__________________
Возможно сделать все. Вопрос времени |
|
18.10.2018, 07:30 | #15 |
Участник
|
я бы такое использовать не стал.
т.е. первое - у вас не будет перекрестных ссылок, они все будут на один метод. этим мне также не нравится подход АХ2012 - его использую только если надо быстро написать одноразовый код. второе - банально неудобно - т.е. мне надо вызвать .inventTable(), я набираю .inv.. и смотрю - есть ли вообще такой метод. В вашем случае будет метод related, который мне надо будет все время открывать и проверять - есть ли там реализация для InventTable третье - как вы уже сами заметили в общем случае связей может быть несколько. т.е. будет .inventTableFrom() .inventTableTo(), и это будет сразу видно при написании кода PS: Но саму идею статей и шаблонов искренне поддерживаю, за это спасибо Последний раз редактировалось trud; 18.10.2018 в 07:36. |
|
18.10.2018, 08:54 | #16 |
Участник
|
|
|
18.10.2018, 09:00 | #17 |
Участник
|
Цитата:
|
|
18.10.2018, 15:04 | #18 |
Участник
|
Спасибо за развернутые ответы.
И да, данное мое решение ориентировано в первую очередь на AX 4, 5 версий. 2012 я уже года 3 как в глаза не видел. Засиделся так сказать на клиенте.))) Релейшены конечно да - это тема. Однако я хотел сделать более просто. Вообще интересный код с рефлексией у Wojzeh. Только если нет relation'а, то нет и результата. А вот если по свойству включаем создание подобных методов, это уже какой-то сахарный костыль...)) Все-таки я за один единый метод, нежели 10 разных.
__________________
// no comments |
|
21.10.2018, 01:47 | #19 |
Участник
|
Программисты такие программисты
- Вы знаете, мне кажется, что натягивать сову на глобус несколько неудобно. Давайте обсудим вариант запихивания глобуса в сову! - Оно, конечно, хорошо, но у Вашего метода есть некоторые недостатки... Есть текущая запись таблицы SalesLine. Вам надо найти связанную с ней запись SalesTable. Что первое в голову приходит? X++: salesTable = SalesTable::find(salesLine.SalesId); Вот ЭТО и есть "генеральная линия партии" и логика работы с таблицами. Собственно Best Practices настойчиво рекомендует создавать метод find() на всех новых таблицах. Куда уж универсальнее-то? Т.е. сама постановка задачи, мягко говоря, идет в разрез с логикой работы с Axapta. Методы на таблицах типа salesLine.SalesTable() создаются либо от непонимания (привычка из другой среды программирования), либо из-за особенностей конкретного обращения к конкретной таблицы (сложность алгоритма, дополнительное поле и т.п.) Иными словами, такой способ организации поиска записи таблицы-родителя в среде Axapta сам по себе является исключением. Нетипичным обращением. Ну, и зачем пытаться вывести некое универсальное решения для исключений? PS: На всякий случай уточню. Это правило для младших версий Axapta (с которыми автор и работает). Для старших - в настоящее время еще нет устоявшихся правил. Все меняется на лету. Даже в рамках одной версии
__________________
- Может, я как-то неправильно живу?! - Отчего же? Правильно. Только зря... |
|
22.10.2018, 09:44 | #20 |
Участник
|
Цитата:
Сообщение от Владимир Максимов
Т.е. сама постановка задачи, мягко говоря, идет в разрез с логикой работы с Axapta. Методы на таблицах типа salesLine.SalesTable() создаются либо от непонимания (привычка из другой среды программирования), либо из-за особенностей конкретного обращения к конкретной таблицы (сложность алгоритма, дополнительное поле и т.п.)
Иными словами, такой способ организации поиска записи таблицы-родителя в среде Axapta сам по себе является исключением. Нетипичным обращением. Ну, и зачем пытаться вывести некое универсальное решения для исключений? PS: На всякий случай уточню. Это правило для младших версий Axapta (с которыми автор и работает). Для старших - в настоящее время еще нет устоявшихся правил. Все меняется на лету. Даже в рамках одной версии Плюс вашего подхода - используем чисто find() и не паримся с доп. методами типа salesLine(). Минус же в том, что вам нужно помнить внешний ключ (SalesId-то все знают, а если рассматривать более редкую таблицу, а если ключ составной?). Плюс моего подхода - такая же унификация по имени метода как и find, но также метод может вернуть любую таблицу, которая там прописана. А find - не может. Другой плюс - нам не нужен ключ к таблице, нам нужна сама таблица.
__________________
// no comments |
|
|
|