Intro

PlantUML для баз даних

Повний гайд по створенню професійних діаграм баз даних за допомогою PlantUML - від ER-діаграм до схем архітектури

PlantUML для баз даних

Вступ: Навіщо потрібен PlantUML?

Якщо ви працювали з ER-діаграмами у попередніх уроках, ви помітили, що візуалізація структури бази даних критично важлива. Але що, якщо вам потрібно:

  • 📊 Складні ER-діаграми з десятками таблиць?
  • 🔄 Автогенерація діаграм з коду?
  • 📝 Версіонування діаграм у Git разом з кодом?
  • 🎨 Професійна візуалізація для документації?

PlantUML - це рішення всіх цих проблем!

PlantUML - це інструмент створення UML та інших діаграм з текстового опису. Замість малювання мишкою ви пишете код, який перетворюється на діаграму.

Порівняння підходів

draw.io, Lucidchart, Visio

✅ Інтуїтивно
✅ WYSIWYG
❌ Важко підтримувати версії
❌ Складно синхронізувати з кодом
❌ Неможливо автогенерувати
❌ Важко робити code review

Встановлення та налаштування

Використання на цьому сайті

На цьому сайті PlantUML вже інтегрований! Використовуйте компонент ::plant-uml:

::plant-uml

\`\`\`plantuml
@startuml
entity Student {
\*id : int
--
name : string
}
@enduml
\`\`\`

::

Локальна робота (опціонально)

Найпростіший спосіб для тестування:

https://www.plantuml.com/plantuml/


Базовий синтаксис

Структура PlantUML файлу

Кожна діаграма починається з @startuml та закінчується @enduml:

@startuml
' Це коментар

' Тут ваша діаграма

@enduml
Коментарі:
  • Одинарна лінія: ' коментар або // коментар
  • Багаторядковий: /' коментар '/

ER-діаграми (Entity-Relationship)

Основний синтаксис

Loading diagram...
@startuml
entity "Student" as student {
  *student_id : int <<PK>>
  --
  name : varchar(100)
  email : varchar(100)
  age : int
}

entity "Course" as course {
  *course_id : int <<PK>>
  --
  title : varchar(100)
  credits : int
}

entity "Enrollment" as enrollment {
  *student_id : int <<FK>>
  *course_id : int <<FK>>
  --
  grade : int
  enrollment_date : date
}

student ||--o{ enrollment
course ||--o{ enrollment
@enduml

Пояснення синтаксису

entity "Назва таблиці" as псевдонім {
  *ключове_поле : тип <<PK>>    // Первинний ключ
  *зовнішній_ключ : тип <<FK>>  // Зовнішній ключ
  --                             // Розділювач
  звичайне_поле : тип
}
Позначення полів:
  • * - обов'язкове поле (NOT NULL)
  • <<PK>> - Primary Key
  • <<FK>> - Foreign Key
  • -- - розділювач між ключами та звичайними полями

Типи зв'язків

Синтаксис PlantUMLКардинальністьЗначенняПриклад
||--||1:1Один до одногоКраїна ↔ Столиця
||--o{1:NОдин до багатьохАвтор → Книги
}o--o{M:NБагато до багатьохСтуденти ↔ Курси
||..o{1:N (опціонально)Необов'язковий зв'язокКлієнт → Замовлення

Легенда символів:

  • || - точно один (обов'язковий)
  • o{ - нуль або багато (опціонально)
  • |{ - один або багато (обов'язково хоч один)

Приклад: E-commerce система

Loading diagram...
@startuml
!theme cerulean-outline

entity "User" as user {
  *user_id : int <<PK>>
  --
  email : varchar(100)
  password_hash : varbinary(128)
  full_name : nvarchar(100)
  created_at : datetime2
}

entity "Product" as product {
  *product_id : int <<PK>>
  --
  name : nvarchar(200)
  description : nvarchar(max)
  price : decimal(10,2)
  stock_quantity : int
  category_id : int <<FK>>
}

entity "Category" as category {
  *category_id : int <<PK>>
  --
  name : nvarchar(100)
  parent_category_id : int <<FK>>
}

entity "Order" as order {
  *order_id : int <<PK>>
  user_id : int <<FK>>
  --
  order_date : datetime2
  total_amount : decimal(10,2)
  status : varchar(20)
}

entity "OrderItem" as order_item {
  *order_item_id : int <<PK>>
  order_id : int <<FK>>
  product_id : int <<FK>>
  --
  quantity : int
  unit_price : decimal(10,2)
}

entity "Review" as review {
  *review_id : int <<PK>>
  product_id : int <<FK>>
  user_id : int <<FK>>
  --
  rating : tinyint
  comment : nvarchar(500)
  created_at : datetime2
}

' Зв'язки
user ||--o{ order : "робить"
user ||--o{ review : "пише"
order ||--|{ order_item : "містить"
product ||--o{ order_item : "входить в"
product ||--o{ review : "має"
category ||--o{ product : "містить"
category ||--o{ category : "підкатегорія"
@enduml
Рядок !theme cerulean-outline застосовує готову тему. Інші теми:
  • sketchy - ескізний стиль
  • vibrant - яскраві кольори
  • toy - іграшковий стиль
  • mars - темна тема

Class Diagram (Діаграми класів для ORM)

Якщо ви використовуєте ORM (Entity Framework, Hibernate), діаграми класів ідеально відображають вашу модель:

Loading diagram...
@startuml
!theme cerulean

class Student {
  +Id : int
  +FirstName : string
  +LastName : string
  +Email : string
  +BirthDate : DateTime
  --
  +GetAge() : int
  +Enroll(course: Course) : void
}

class Course {
  +Id : int
  +Title : string
  +Credits : int
  +Description : string
  --
  +GetEnrolledStudents() : List<Student>
}

class Enrollment {
  +StudentId : int
  +CourseId : int
  +EnrollmentDate : DateTime
  +Grade? : decimal
  --
  +IsCompleted() : bool
}

class Professor {
  +Id : int
  +Name : string
  +Department : string
  --
  +GetCourses() : List<Course>
}

Student "1" -- "*" Enrollment : enrolls
Course "1" -- "*" Enrollment : has
Professor "1" -- "*" Course : teaches
@enduml

Модифікатори доступу

СимволМодифікаторC#Java
+Publicpublicpublic
-Privateprivateprivate
#Protectedprotectedprotected
~Package/Internalinternalpackage-private

Component Diagram (Архітектура системи)

Використовуйте для відображення архітектури вашого застосунку:

Loading diagram...
@startuml
!theme sketchy

package "Presentation Layer" {
  [Web API Controllers]
  [Blazor Components]
}

package "Application Layer" {
  [Use Cases / Services]
  [DTOs]
  [Validators]
}

package "Domain Layer" {
  [Entities]
  [Value Objects]
  [Domain Services]
  [Repositories Interfaces]
}

package "Infrastructure Layer" {
  [EF Core DbContext]
  [Repository Implementations]
  [External APIs]
}

database "SQL Server" {
  [Tables]
  [Stored Procedures]
  [Views]
}

[Web API Controllers] --> [Use Cases / Services]
[Blazor Components] --> [Use Cases / Services]
[Use Cases / Services] --> [Entities]
[Use Cases / Services] --> [Repositories Interfaces]
[Repositories Interfaces] <|.. [Repository Implementations]
[Repository Implementations] --> [EF Core DbContext]
[EF Core DbContext] --> [Tables]
@enduml

Sequence Diagram (Діаграми послідовності)

Ідеально для документування бізнес-процесів та API flows:

Loading diagram...
@startuml
!theme vibrant

actor User
participant "Web App" as App
participant "API Gateway" as API
participant "Auth Service" as Auth
participant "Order Service" as Order
database "Database" as DB

User -> App: Натискає "Купити"
App -> API: POST /api/orders
API -> Auth: Перевіряє токен
Auth --> API: Токен валідний

API -> Order: CreateOrder(userId, items)
Order -> DB: BEGIN TRANSACTION
Order -> DB: INSERT INTO Orders
Order -> DB: INSERT INTO OrderItems
Order -> DB: UPDATE Products SET stock -= qty
Order -> DB: COMMIT

DB --> Order: Success
Order --> API: OrderId: 12345
API --> App: {"orderId": 12345, "status": "created"}
App --> User: "Замовлення оформлено!"
@enduml

Практичний кейс: Database Transaction

Loading diagram...
@startuml
participant "Application" as App
database "SQL Server" as DB

App -> DB: BEGIN TRANSACTION
activate DB

App -> DB: SELECT * FROM Accounts\nWHERE account_id = 1\nFOR UPDATE
DB --> App: Balance: $1000

App -> App: Validate balance >= $100

App -> DB: UPDATE Accounts\nSET balance = balance - 100\nWHERE account_id = 1
DB --> App: 1 row affected

App -> DB: UPDATE Accounts\nSET balance = balance + 100\nWHERE account_id = 2
DB --> App: 1 row affected

App -> DB: INSERT INTO Transactions\nVALUES (...)
DB --> App: Transaction logged

App -> DB: COMMIT
deactivate DB
DB --> App: Transaction successful
@enduml

Deployment Diagram (Діаграма розгортання)

Показує фізичну інфраструктуру та розміщення компонентів:

Loading diagram...
@startuml
!theme mars

node "Load Balancer" as lb {
  [Nginx]
}

node "App Server 1" as app1 {
  [.NET Web API]
  [Redis Cache]
}

node "App Server 2" as app2 {
  [.NET Web API]
  [Redis Cache]
}

node "Database Cluster" as db_cluster {
  database "Primary DB" as primary
  database "Replica 1" as replica1
  database "Replica 2" as replica2
}

cloud "Azure Storage" as storage {
  [Blob Storage]
}

lb --> app1 : HTTPS
lb --> app2 : HTTPS

app1 --> primary : Write
app1 --> replica1 : Read
app2 --> primary : Write
app2 --> replica2 : Read

primary --> replica1 : Replication
primary --> replica2 : Replication

app1 --> storage : Upload files
app2 --> storage : Upload files
@enduml

Стилізація та кастомізація

Кольори та стилі

Loading diagram...
@startuml
skinparam backgroundColor #F0F0F0
skinparam shadowing false

skinparam entity {
  BackgroundColor LightBlue
  BorderColor DarkBlue
  FontSize 14
}

skinparam arrow {
  Color DarkGreen
  Thickness 2
}

entity "User" as user {
  *user_id : int
  --
  name : string
}

entity "Order" as order {
  *order_id : int
  --
  total : decimal
}

user ||--o{ order
@enduml

Підсвічування критичних елементів

Loading diagram...
@startuml
!theme cerulean

entity "User" as user #LightGreen {
  *user_id : int <<PK>>
  --
  email : varchar(100)
  password_hash : varbinary(128)
}

entity "PaymentMethod" as payment #LightCoral {
  *payment_id : int <<PK>>
  user_id : int <<FK>>
  --
  card_number : varchar(20)
  cvv : char(3)
}

note right of payment #FFAAAA
  ⚠️ КРИТИЧНО:
  Небезпечно зберігати CVV!
  Використовуйте tokenization
end note

user ||--o{ payment
@enduml

Практичні приклади

Приклад 1: Університет (повна ER-модель)

Loading diagram...
@startuml
!theme cerulean-outline

entity "Student" as student {
  *student_id : int <<PK>>
  --
  first_name : nvarchar(50)
  last_name : nvarchar(50)
  email : varchar(100)
  birth_date : date
  enrollment_year : int
}

entity "Professor" as professor {
  *professor_id : int <<PK>>
  --
  name : nvarchar(100)
  department : varchar(50)
  hire_date : date
}

entity "Course" as course {
  *course_id : int <<PK>>
  professor_id : int <<FK>>
  --
  title : nvarchar(100)
  credits : tinyint
  semester : varchar(20)
}

entity "Enrollment" as enrollment {
  *student_id : int <<FK>>
  *course_id : int <<FK>>
  --
  enrollment_date : date
  grade : decimal(3,2)
  status : varchar(20)
}

entity "Classroom" as classroom {
  *classroom_id : int <<PK>>
  --
  building : varchar(10)
  room_number : varchar(10)
  capacity : int
}

entity "Schedule" as schedule {
  *schedule_id : int <<PK>>
  course_id : int <<FK>>
  classroom_id : int <<FK>>
  --
  day_of_week : varchar(10)
  start_time : time
  end_time : time
}

student ||--o{ enrollment
course ||--o{ enrollment
professor ||--o{ course
course ||--o{ schedule
classroom ||--o{ schedule
@enduml

Приклад 2: Бібліотека

Loading diagram...
@startuml
entity "Book" as book {
  *isbn : varchar(13) <<PK>>
  --
  title : nvarchar(200)
  publication_year : int
  pages : int
  publisher_id : int <<FK>>
}

entity "Author" as author {
  *author_id : int <<PK>>
  --
  name : nvarchar(100)
  birth_year : int
  country : varchar(50)
}

entity "BookAuthor" as book_author {
  *book_isbn : varchar(13) <<FK>>
  *author_id : int <<FK>>
}

entity "Publisher" as publisher {
  *publisher_id : int <<PK>>
  --
  name : nvarchar(100)
  country : varchar(50)
}

entity "Member" as member {
  *member_id : int <<PK>>
  --
  name : nvarchar(100)
  email : varchar(100)
  join_date : date
}

entity "Loan" as loan {
  *loan_id : int <<PK>>
  book_isbn : varchar(13) <<FK>>
  member_id : int <<FK>>
  --
  loan_date : date
  due_date : date
  return_date : date
}

book }o--o{ author
book }o--|| publisher
book ||--o{ loan
member ||--o{ loan
book ||--o{ book_author
author ||--o{ book_author
@enduml

Генерація PlantUML з бази даних

З SQL Server

PowerShell скрипт для генерації ER-діаграми:

# GetPlantUMLFromDatabase.ps1
$server = "localhost"
$database = "MyDatabase"

$query = @"
SELECT
    t.name AS TableName,
    c.name AS ColumnName,
    ty.name AS DataType,
    c.is_nullable AS IsNullable,
    CASE WHEN pk.column_id IS NOT NULL THEN 1 ELSE 0 END AS IsPK,
    CASE WHEN fk.parent_column_id IS NOT NULL THEN 1 ELSE 0 END AS IsFK
FROM sys.tables t
INNER JOIN sys.columns c ON t.object_id = c.object_id
INNER JOIN sys.types ty ON c.user_type_id = ty.user_type_id
LEFT JOIN (
    SELECT ic.object_id, ic.column_id
    FROM sys.indexes i
    INNER JOIN sys.index_columns ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id
    WHERE i.is_primary_key = 1
) pk ON c.object_id = pk.object_id AND c.column_id = pk.column_id
LEFT JOIN sys.foreign_key_columns fk ON c.object_id = fk.parent_object_id AND c.column_id = fk.parent_column_id
ORDER BY t.name, c.column_id
"@

# Виконати запит та згенерувати PlantUML
# (код спрощено для прикладу)

З Entity Framework Core

C# код для генерації з DbContext:

using Microsoft.EntityFrameworkCore;
using System.Text;

public static class PlantUmlGenerator
{
    public static string GenerateFromDbContext(DbContext context)
    {
        var sb = new StringBuilder();
        sb.AppendLine("@startuml");
        sb.AppendLine("!theme cerulean-outline");
        sb.AppendLine();

        var entityTypes = context.Model.GetEntityTypes();

        foreach (var entityType in entityTypes)
        {
            sb.AppendLine($"entity \"{entityType.ClrType.Name}\" as {entityType.ClrType.Name.ToLower()} {{");

            var properties = entityType.GetProperties();
            foreach (var prop in properties)
            {
                var isPK = prop.IsPrimaryKey() ? " <<PK>>" : "";
                var isFK = prop.IsForeignKey() ? " <<FK>>" : "";
                var asterisk = !prop.IsNullable ? "*" : " ";

                sb.AppendLine($"  {asterisk}{prop.Name} : {prop.ClrType.Name}{isPK}{isFK}");
            }

            sb.AppendLine("}");
            sb.AppendLine();
        }

        // Генерація зв'язків
        foreach (var entityType in entityTypes)
        {
            var navigations = entityType.GetNavigations();
            foreach (var nav in navigations)
            {
                if (nav.IsCollection)
                {
                    sb.AppendLine($"{entityType.ClrType.Name.ToLower()} ||--o{{ {nav.TargetEntityType.ClrType.Name.ToLower()}");
                }
            }
        }

        sb.AppendLine("@enduml");
        return sb.ToString();
    }
}

Поради та best practices

Для довгих назв таблиць використовуйте короткі псевдоніми:
entity "UserAuthenticationHistory" as uah {
  ...
}

user ||--o{ uah : "має історію"
package "User Management" {
  entity User
  entity Role
  entity Permission
}

package "E-commerce" {
  entity Product
  entity Order
}
' === CORE ENTITIES ===
entity User { ... }

' === JUNCTION TABLES ===
entity UserRole { ... }
entity User {
  password_hash : varbinary(128)
}

note right of User
  Використовується bcrypt
  з work factor = 12
end note
  • Максимум 10-15 сутностей на одній діаграмі
  • Розбивайте велику систему на модулі
  • Створюйте окремі діаграми для різних bounded contexts

Експорт та інтеграція

Формати експорту

PlantUML підтримує:

  • SVG - векторна графіка (рекомендовано для web)
  • PNG - растрова графіка
  • PDF - для документації
  • LaTeX - для наукових робіт
  • ASCII Art - текстове представлення

Інтеграція з Git

Додайте .puml файли у версіонування:

project/
├── docs/
│   ├── diagrams/
│   │   ├── database-er.puml
│   │   ├── architecture.puml
│   │   └── api-flow.puml
│   └── README.md
├── src/
└── .gitignore

CI/CD генерація діаграм

GitHub Actions приклад:

name: Generate Diagrams

on: [push]

jobs:
    generate:
        runs-on: ubuntu-latest
        steps:
            - uses: actions/checkout@v2
            - name: Generate PlantUML diagrams
              uses: cloudbees/plantuml-github-action@master
              with:
                  args: -v -tsvg docs/diagrams/*.puml
            - name: Commit diagrams
              run: |
                  git config user.name "GitHub Actions"
                  git add docs/diagrams/*.svg
                  git commit -m "Update diagrams" || true
                  git push

Ресурси та інструменти

Онлайн інструменти

Документація

Інтеграції

  • VS Code: PlantUML Extension
  • IntelliJ IDEA: PlantUML integration plugin
  • Confluence: PlantUML macro
  • GitLab: Підтримка .puml у markdown
  • Notion: Через PlantUML сервер

Завдання для практики

Створіть ER-діаграму для системи управління проєктами:Сутності:
  • Project (назва, опис, дата початку)
  • Task (назва, опис, статус, пріоритет)
  • User (ім'я, email, роль)
  • Comment (текст, дата створення)
Зв'язки:
  • Проєкт має багато задач
  • Користувач може бути призначений на багато задач
  • Задача може мати багато коментарів
  • Користувач може писати багато коментарів
Створіть діаграму архітектури для:
  • Web API (.NET)
  • PostgreSQL база даних
  • Redis кеш
  • RabbitMQ черга повідомлень
  • S3 сховище файлів
Покажіть взаємодію між компонентами.

Висновок

PlantUML - це потужний інструмент для:

✅ Документування структури БД
✅ Проектування нових систем
✅ Комунікації в команді
✅ Автоматизації генерації діаграм
✅ Підтримки документації в актуальному стані

Золоте правило: Діаграма має бути зрозумілою без додаткових пояснень. Якщо вона занадто складна - розбийте на кілька простіших!

Наступні кроки:

  1. Спробуйте створити ER-діаграму для вашого проєкту
  2. Інтегруйте PlantUML у вашу документацію
  3. Налаштуйте автогенерацію діаграм у CI/CD
  4. Поділіться досвідом з командою!
Copyright © 2026