gsbelarus / gdmn

GDMN — это революционная облачная платформа с открытым исходным кодом для создания приложений автоматизации учета/управления на предприятии.
MIT License
18 stars 0 forks source link

Формирование запроса для вывода на экран осмысленных данных Entity #108

Open gsbelarus opened 5 years ago

gsbelarus commented 5 years ago

В реляционной БД ссылки на другие сущности это просто целочисленные поля. Пользователю будет мало толку, если вывести их на экран в гриде.

Как ведет себя Гедымин, когда формирует запрос для выборки данных сущности:

  1. Он включает все поля сущности, в том числе и поля внешние ключи. Их целочисленные значения в последствии используются во многих местах программы, в частности при организации работы элементов управления пользовательского интерфейса.
  2. Далее, для каждой ссылки в запрос добавляется JOIN или LEFT JOIN на соответствующую таблицу.
  3. В SELECT часть запроса добавляется из присоединенной таблицы поле с наименованием объекта. Чаще всего это поле NAME или USR$NAME, но может быть и другое. Программист для каждого класса может указать свое.

Теперь рассмотрим как Гедымин разбирается с ситуациями, когда поле ссылка может содержать ссылки на объекты разного типа. Например, поле ссылка -- это внешний ключ на таблицу GD_CONTACT и, соответственно, может содержать ссылки на объекты Компания, Банк, Человек, Сотрудник предприятия, Подразделение.

В Гедымине для всех таких объектов будет один общий родитель -- это класс TgdcBaseContact и у него свойство ListTable будет указано как GD_CONTACT.

Например, пользователь хочет открыть диалоговое окно для редактирования объекта, ИД которого лежит в поле, по которому создан внешний ключ на таблицу GD_CONTACT. Такая ситуация возникает по тысяче раз в день, когда пользователь нажимает клавишу F4 (редактирование объекта) в выпадающем списке.

  1. Гедымин посмотрит куда ведет ссылка (на таблицу GD_CONTACT) и в специальном списке (аналог нашей ER Model) найдет наиболее общий класс, у которого ListTable указан как GD_CONTACT.
  2. Этим классом будет в данном случае TgdcBaseContact. Будет создан его экземпляр с подмножеством ByID и открыт. Т.е. выполнен запрос к базе данных и найдена запись по указанному ИД.
  3. Для данного экземпляра, для текущей в нем записи, будет вызван метод EditDialog.
  4. Этот метод вызовет внутри себя метод GetCurrRecordClass. Этот метод зависит от каждого класса. Например для контактов он будет смотреть на поле CONTACTTYPE. Для базового типа документов, этот метод посмотрит на поле documenttypekey и по нему найдет в списке документов класс уже конкретного документа.
  5. Например, конкретный ИД -- это ИД банка(т.е. CONTACTTYPE=5). Тогда функция GetCurrRecordClass вернет TgdcBank.
  6. Так как TgdcBank <> TgdcBaseContact, то будет создан экземпляр уже TgdcBank в нем выбрана запись по указанному ИД и уже для этого объекта вызван метод EditDialog.
gsbelarus commented 5 years ago

Чтобы не заблудиться в трех соснах, разделим задачу на три части:

  1. Отображение заданных атрибутов из EntityAttribute в выборке.
  2. Извлечение данных Entity по заданному ИД из EntityAttribute, допускающему несколько типов Entity.
  3. Формирование условий выборки записей Entity по атрибутам EntityAttribute.
gsbelarus commented 5 years ago

1a

Предположим, перед нами стоит задача реализовать следующий пользовательский интерфейс:

  1. Отобразить на экране список накладных на реализацию нашей продукции.
  2. В списке документов, среди прочих атрибутов документа, мы хотим видеть Наименование покупателя и Телефон покупателя.
  3. Рядом со списком необходимо отобразить панель, где для покупателя из текущей позиции в списке документов, показывать историю его покупок и платежей.

Сначала рассмотрим простой вариант, когда у сущности Накладная EntityAttribute покупателя содержит только одну сущность Компания.

При формировании SQL запроса система должна присоединить по JOIN или LEFT JOIN (в зависимости от того, обязательным или нет является атрибут) таблицу(ы) из сущности компания, содержащие заданные атрибуты и вытащить их в часть SELECT запроса.

Для нашей структуры БД части SQL запроса будут выглядеть следующим образом:

SELECT 
  ...
  z.customerkey,
  c.name,
  c.phone
  ...
FROM
  <таблица накладной> z
  JOIN gd_contact c ON z.customerkey = c.id
  ...

если же будет задано показать Наименование и УНП, которые лежат в разных таблицах, то запрос примет следующий вид:

SELECT 
  ...
  z.customerkey,
  c.name,
  t.taxid
  ...
FROM
  <таблица накладной> z
  JOIN gd_contact c ON z.customerkey = c.id
  JOIN gd_companycode t ON z.customerkey = t.contactkey
  ...

Следует обратить внимание, что мы также вытаскиваем в запросе ИД компании. При перемещении по таблице мы будем использовать этот ИД для того, чтобы формировать запросы на определение истории покупок и платежей клиента.