Многолетним
лидером
в построении моделей данных является система SAP (ранее Sybase) PowerDesigner (PD).
В своей деятельности у меня получилось "совместить" логическую (Logical Data Model (LDM) и физическую (Physical Data Model (PDM)
модели данных благодаря замечательной особенности PD - возможности расширения моделей, в частности, PDM.
Вот как выглядит фрагмент одной из доработанных ER-диаграмм:
Диаграмма «Сущность-Связь» описывает сущности (таблицы) и атрибуты (столбцы), а также связи между сущностями.
Качественная, подробная модель данных рассказывает как устроен бизнес, а ER-диаграмма - экспресс-взгляд на бизнес.
Как кастомизировать физическую модель данных? Разберём на рабочем примере со многими содержательными картинками.
Прежде всего настраиваем опцию визуализации ER-диаграмм.
Идем в главное меню: Tools -> Model Options -> в окне слева в дереве выбираем "Naming Convertion" ->
справа, вверху радиокнопки "Display": Name (бизнес-наименования пишем на русском) или Code (системные наименования пишем на английском) полей, выбираем бизнес-наименование.
Каждый объект моделей любого типа в SAP PowerDesigner имеет обязательные уникальные Name и Code.
Мы будем использовать понятные бизнесу наименования, придерживаясь корпоративного глоссария.
Поскольку в списочных представлениях многих систем отчетности, управления базами данных, BI-разработки, Data Tools
объекты упорядочиваются по алфавиту, то и в Name и в Code ключевые слова выносим в начало наименований.
Например, Договора номер, Договора дата, Договора статус.
Существенная выгода от упрощения кросс-функциональных коммуникаций будет, если далее эти наименования распространять в разрабатываемые системы,
в частности, Name - как заголовки (Caption) столбцов в отчетах, как подписи (Label) полей в экранных формах.
Расширение создается по нажатию правой кнопки мыши в разделе «Extensions» и хранится в файле модели.
Вообще все добавления в расширение инициируются по нажатию правой кнопки мыши.
В созданное расширение добавим базовый метакласс «Table», а затем будем настраивать его свойства и методы.
Впоследствии в модели данных этот метакласс нужно применять при создании таблиц, на которые будут автоматически распространяться произведенные настройки.
Добавим дополнительные атрибуты метакласса «Table», которые могут иметь различные типы данных, в том числе строковый с выбором из предопределённого списка.
Так, атрибут «Предметная область» позволит классифицировать таблицы модели по областям бизнеса, а также можно прописать в обработчике код, который будет раскрашивать
соответствующие им графические объекты в ER-диаграммах.
Для дополнительного атрибута можно сформировать набор иконок, которые будут отображаться на ER-диаграмме в зависимости от значения атрибута.
Например, атрибутом «Процент готовности» будем информировать о стадии завершенности проектирования таблицы.
Дополнительные атрибуты могут быть вычисляемыми как посредством утилизации метода Get:
так и посредством употребления готовой агрегатной метрики:
В разделе «Stereotypes» сотворим новый стереотип Stereotype_Table и включим опцию «Toolbox custom tool»,
чтобы в панели инструментов для ER-диаграмм появилась выбранная нами иконка метакласса.
Именно в стереотипе для метакласса можно создать кастомный графический символ (Custom Symbol), который будет отображаться на ER-диаграммах.
Конкретизируем контент графического символа: размер символа, стили линий, цвета фона, теней, вид шрифта для каждого атрибута и собственно содержание Custom Symbol.
Здесь, в вёрстке важно задействовать те атрибуты и коллекции, которые будут точно полезны на ER-диаграммах, не перегружая её информацией.
Сохраненные изменения в метаклассе будут автоматически применены к объектам модели, которые унаследованы от этого метакласса.
Для объектов модели можно создать новые и переопределить существующие экранные формы-карточки, вытягивая на них ранее созданные дополнительные атрибуты и коллекции.
Форма-карточка открывается в модальном режиме при двойном клике мыши на графическом символе ER-диаграммы или на строке в списочной форме.
Вот так можно изменить (см. ниже) основную форму для объектов «Таблица». Видоизмененная форма показывается тогда,
когда заполнен атрибут «Stereotype».
На других вкладках задействованы коллекции ключей (Keys), индексов (Indexes) и родительских & подчиненных таблиц.
Добавив в расширение модели метаклассы «Column», «Reference», «View» и др., их можно кастомизировать аналогично.
Например, вот так была переопределена основная форма для поля (полей) таблицы с добавлением на неё дополнительных атрибутов:
Объекты метаклассов имеют собственные события, для которых можно программировать обработчики на языке VBScript.
Например, событие Validate возникает при нажатии кнопок «ОК», «Применить» в форме-карточке объекта или при переходе к другой строке
для измененной строки в списочной форме объектов. Можно перехватывать это событие, выполнять какие-то действия, проверять значения атрибутов
и либо позволять ( %Validate% = True ), либо отменять ( %Validate% = False ) изменения.
Благодаря развитой объектной модели SAP PowerDesigner дозволяет разрабатывать собственные методы (см. раздел «Methods») на языке VBScript
и подключать их в контекстное меню
(см. раздел «Menus») для объектов метакласса, т.е. в меню, которое показывается по щелчку правой кнопки мыши на графическом символе объекта.
Ниже приведены два рабочих метода:
-
• Импорт описаний полей и таблиц из подготовленного файла Excel;
-
• Создание RI-связей между таблицами из подготовленного файла Excel и их отрисовка в ER-диаграмме.
Sub %Method%(obj)
' Импорт описаний полей и таблиц из подготовленного файла Excel
Dim model
Dim tab
Dim col
Dim objExcel
Dim wBook
Dim ExcelFileFullName
Dim fso
Dim i, tblOwner, tblCode, tblComm, clnCode, clnComm, WhatDo
Set model = ActiveModel ' Current active model
If (model Is Nothing) Or (Not model.IsKindOf(PdPDM.cls_Model)) Then
MsgBox "Текущая модель НЕ является физической моделью данных (PDM)"
Exit sub
End If
ExcelFileFullName = TRIM(InputBox("Введите полное (включая путь) имя Excel-файла с описаниями полей и таблиц. Шаблон вида:" & vbNewLine & vbNewLine _
& "В первой строке 1-го листа Excel - наименования столбцов (наименования могут быть произвольными), в следующих строках:" & vbNewLine _
& "1-ый столбец - Owner таблицы" & vbNewLine _
& "2-ой столбец - Системное имя таблицы" & vbNewLine _
& "3-ий столбец - Комментарий к таблице (должен быть заполнен в строке только один раз для последнего поля каждой таблицы!" & vbNewLine _
& "4-ый столбец - Системное имя поля" & vbNewLine _
& "5-ый столбец - Комментарий к полю" ))
IF ExcelFileFullName = "" Then
Exit sub
End If
Set fso = CreateObject("Scripting.FileSystemObject")
If fso.FileExists(ExcelFileFullName) Then
Else
MsgBox "НЕ существует файла " & ExcelFileFullName
Exit sub
End If
WhatDo = MsgBox("Импортировать описания полей и таблиц:" & vbNewLine & vbNewLine _
& "ДА - добавить к уже существующим описаниям в модели" & vbNewLine _
& "НЕТ - заместить, обновить описания из файла" , 4 + 32, "")
Set objExcel = CreateObject("Excel.Application")
objExcel.Visible = True
Set wBook = objExcel.Workbooks.Open(ExcelFileFullName)
For i = 2 To 64000
If TRIM(wBook.Sheets(1).Cells(i, 2)) = "" Then
Exit For ' выход из цикла, если закончился список полей в Excel-файле
End if
tblOwner = TRIM(wBook.Sheets(1).Cells(i, 1)) ' Owner таблицы
tblCode = TRIM(wBook.Sheets(1).Cells(i, 2)) ' системное имя таблицы
tblComm = TRIM(wBook.Sheets(1).Cells(i, 3)) ' Комментарий к таблице
clnCode = TRIM(wBook.Sheets(1).Cells(i, 4)) ' Системное имя поля
clnComm = TRIM(wBook.Sheets(1).Cells(i, 5)) ' Комментарий к полю
For Each tab In ActiveModel.tables
If UCase(tblCode) = UCase(TRIM(tab.Code)) AND Instr(UCase(tab.Owner), UCase(tblOwner)) > 0 AND NOT tab.isShortcut Then
If WhatDo = 6 Then
tab.SetAttribute "Comment", TRIM( TRIM(tab.GetAttribute("Comment")) & " " & tblComm )
Else
tab.SetAttribute "Comment", tblComm
End if
For Each col In tab.columns
If UCase(clnCode) = UCase(TRIM(col.Code)) Then
output tab.Code & "." & col.Code & " Комментарий к полю: " & col.Comment & " ДОБАВЛЯЕТСЯ: " & clnComm
If WhatDo = 6 Then
col.SetAttribute "Comment", TRIM( TRIM(col.GetAttribute("Comment")) & " " & clnComm )
Else
col.SetAttribute "Comment", clnComm
End if
End if
Next
End if
Next ' цикл по таблицам модели
Next
wBook.Close ' обязательно осовбождаем ресурсы при завершении процедуры
Set objExcel = Nothing ' обязательно осовбождаем ресурсы при завершении процедуры
MsgBox "Завершен импорт описаний полей и таблиц из файла " & ExcelFileFullName
End Sub
Sub %Method%(obj)
' Создание RI-связей между таблицами из подготовленного файла Excel и их отрисовка в ER-диаграмме
Dim mdl
Dim prntTbl
Dim prntCol
Dim chldTbl
Dim chldCol
Dim prnt
Dim Pcolumn
Dim chld
Dim Ccolumn
Dim ref
Dim newRef
Dim refFound
Dim joins
Dim j
Dim symbl
Dim ExcelFileFullName
Dim fso
Dim objExcel
Dim wBook
Dim i
Dim tab
Dim tblOwner
SET mdl = ActiveModel
If (mdl Is Nothing) Or (Not mdl.IsKindOf(PdPDM.cls_Model)) Then
MsgBox "Текущая модель НЕ является физической моделью данных (PDM)"
Exit sub
End If
ExcelFileFullName = TRIM(InputBox("Введите полное (включая путь) имя Excel-файла с описаниями полей и таблиц. Шаблон вида:" & vbNewLine & vbNewLine _
& "В первой строке 1-го листа Excel - наименования столбцов (наименования могут быть произвольными), в следующих строках:" & vbNewLine _
& "1-ый столбец - Owner таблиц" & vbNewLine _
& "2-ой столбец - Системное имя (родительской) Parent-таблицы" & vbNewLine _
& "3-ий столбец - Системное имя PK-поля Parent-таблицы" & vbNewLine _
& "4-ый столбец - Системное имя (подчиненной) Child-таблицы" & vbNewLine _
& "5-ый столбец - Системное имя FK-поля Child-таблицы" ))
IF ExcelFileFullName = "" Then
Exit sub
End If
Set fso = CreateObject("Scripting.FileSystemObject")
If fso.FileExists(ExcelFileFullName) Then
Else
MsgBox "НЕ существует файла " & ExcelFileFullName
Exit sub
End If
Set objExcel = CreateObject("Excel.Application")
objExcel.Visible = True
Set wBook = objExcel.Workbooks.Open(ExcelFileFullName)
For i = 2 To 64000
If TRIM(wBook.Sheets(1).Cells(i, 2)) = "" Then
Exit For ' выход из цикла, если закончился список полей в Excel-файле
End if
tblOwner = TRIM(wBook.Sheets(1).Cells(i, 1)) ' Owner таблиц
prntTbl = TRIM(wBook.Sheets(1).Cells(i, 2)) ' системное имя Parent-таблицы
prntCol = TRIM(wBook.Sheets(1).Cells(i, 3)) ' системное имя поля (PK) Parent-таблицы
chldTbl = TRIM(wBook.Sheets(1).Cells(i, 4)) ' системное имя Child-таблицы
chldCol = TRIM(wBook.Sheets(1).Cells(i, 5)) ' cистемное имя поля (FK) Child-таблицы
refFound = False
For Each ref In mdl.References
refFound = False
SET joins = ref.Joins
For Each j In joins
If Instr(UCase(ref.ParentTable.Owner), UCase(tblOwner)) > 0 _
AND UCase(ref.ParentTable.Code) = UCase(prntTbl) AND UCase(j.ParentTableColumn.Code) = UCase(prntCol) _
AND Instr(UCase(ref.ChildTable.Owner), UCase(tblOwner)) > 0 _
AND UCase(ref.ChildTable.Code) = UCase(chldTbl) AND UCase(j.ChildTableColumn.Code) = UCase(chldCol) Then
'output "НАЙДЕНО: " & ref.ParentTable.Owner & "." & ref.ParentTable.Code & "." & j.ParentTableColumn.Code & " " & ref.ChildTable.Owner & "." &
ref.ChildTable.Code & "." & j.ChildTableColumn.Code
refFound = True
Else
'output "-- НЕ НАЙДЕНО: " & ref.ParentTable.Owner & "." & ref.ParentTable.Code & "." & j.ParentTableColumn.Code & " " & ref.ChildTable.Owner & "." &
ref.ChildTable.Code & "." & j.ChildTableColumn.Code
End if
Next
If refFound Then
Exit For
End if
Next ' поиск среди возможно уже существующих RI-связей; если refFound = False, то далее пытаемся создать новую связь между таблицами в модели
SET prnt = Nothing
SET Pcolumn = Nothing
SET chld = Nothing
SET Ccolumn = Nothing
If refFound = False Then
For Each tab In mdl.tables
If UCase(prntTbl) = UCase(TRIM(tab.Code)) AND Instr(UCase(tab.Owner), UCase(tblOwner)) > 0 AND NOT tab.isShortcut Then
SET prnt = tab
exit for
End if
Next
If Not prnt Is Nothing Then
' FindChildByCode(ByVal ChildCode As String,
' ByVal ChildKind As Long,
' ByVal Stereotype As String = "",
' ByVal LastFound As BaseObject = Nothing,
' ByVal CaseSensitive As Boolean = True,
' ByVal IncludeShortcuts As Boolean = False) As BaseObject
SET Pcolumn = prnt.findChildByCode(prntCol, cls_Column, "", Nothing, False, False)
For Each tab In mdl.tables
If UCase(chldTbl) = UCase(TRIM(tab.Code)) AND Instr(UCase(tab.Owner), UCase(tblOwner)) > 0 AND NOT tab.isShortcut Then
SET chld = tab
exit for
End if
Next
If Not chld Is Nothing Then
SET Ccolumn = chld.findChildByCode(chldCol, cls_Column, "", Nothing, False, False)
End if
End if
If prnt Is Nothing OR Pcolumn Is Nothing OR chld Is Nothing OR Ccolumn Is Nothing Then
output "----- НЕТ ОБЪЕКТОВ или ПОЛЕЙ в текущей модели: " & prntTbl & "." & prntCol & " , " & chldTbl & "." & chldCol
Else
SET newRef = mdl.references.CreateNew()
newRef.name = "Связь_" + chld.name + "__" + prnt.name
newRef.code = "ref_" + chld.code + "__" + prnt.code
newRef.ForeignKeyConstraintName = "fk_" + chld.code + "__" + prnt.code
SET newRef.ParentTable = prnt
SET newRef.childTable = chld
SET joins = newRef.Joins
For Each j In joins
SET j.ChildTableColumn = cColumn
Next
SET symbl = ActiveDiagram.AttachLinkObject(newRef) ' Показываем связь на текущей диаграмме
output "В текущей модели создана связь между: " & tblOwner & "." & prntTbl & "." & prntCol & " и " & tblOwner & "." & chldTbl & "." & chldCol
End if
End if
Next ' переход к следующей строке Excel-таблицы
wBook.Close ' обязательно осовбождаем ресурсы при завершении процедуры
Set objExcel = Nothing ' обязательно осовбождаем ресурсы при завершении процедуры
MsgBox "Завершен импорт связей между таблицами из файла " & ExcelFileFullName
End Sub
В качестве бонуса: как посмотреть списком все поля физической модели данных? Идем в главное меню: Model -> Columns...
Списочная (Grid) форма показывает все поля всех таблиц модели, в том числе в список можно включить дополнительные атрибуты полей.
Подобные формы существуют и для других типов объектов модели.
Списочные формы обладают богатой функциональностью: щелкайте на иконки, заголовки столбцов и указатели строк.
Так, захватывая мышью заголовки столбцов, можно их перещать, изменять порядок представления полей.
Выделив несколько указателей строк и нажав Ctrl+C / Delete, можно скопировать в буфер обмена / удалить поля из модели.
Как видно из примера SAP PowerDesigner позволяет адаптировать модели настолько широко, насколько хватает конструктивной фантазии.