{"id":18931775,"url":"https://github.com/nixel2007/entity","last_synced_at":"2025-08-02T21:35:07.299Z","repository":{"id":33645098,"uuid":"148552641","full_name":"nixel2007/entity","owner":"nixel2007","description":"OneScript Persistence API","archived":false,"fork":false,"pushed_at":"2025-03-27T19:55:47.000Z","size":550,"stargazers_count":36,"open_issues_count":24,"forks_count":11,"subscribers_count":11,"default_branch":"master","last_synced_at":"2025-06-01T13:08:16.920Z","etag":null,"topics":["orm","oscript","oscript-lib","oscript-package"],"latest_commit_sha":null,"homepage":"","language":"1C Enterprise","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nixel2007.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"custom":["https://t.me/tribute/app?startapp=sdzj","https://t.me/tribute/app?startapp=d7Rs"],"github":"nixel2007","ko_fi":"nixel2007","patreon":"nixel2007"}},"created_at":"2018-09-12T23:05:36.000Z","updated_at":"2025-03-27T19:55:46.000Z","dependencies_parsed_at":"2024-03-19T19:31:32.378Z","dependency_job_id":"9ad410af-f9d9-484a-9346-cd350d16ff7d","html_url":"https://github.com/nixel2007/entity","commit_stats":null,"previous_names":[],"tags_count":20,"template":false,"template_full_name":null,"purl":"pkg:github/nixel2007/entity","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nixel2007%2Fentity","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nixel2007%2Fentity/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nixel2007%2Fentity/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nixel2007%2Fentity/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nixel2007","download_url":"https://codeload.github.com/nixel2007/entity/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nixel2007%2Fentity/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":268457055,"owners_count":24253337,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-02T02:00:12.353Z","response_time":74,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["orm","oscript","oscript-lib","oscript-package"],"created_at":"2024-11-08T11:46:39.706Z","updated_at":"2025-08-02T21:35:07.257Z","avatar_url":"https://github.com/nixel2007.png","language":"1C Enterprise","readme":"# entity - OneScript Persistence API\n\n\u003ca id=\"header\" /\u003e\n\n[![GitHub release](https://img.shields.io/github/release/nixel2007/entity.svg?style=flat-square)](https://github.com/nixel2007/entity/releases)\n[![GitHub license](https://img.shields.io/github/license/nixel2007/entity.svg?style=flat-square)](https://github.com/nixel2007/entity/blob/develop/LICENSE.md)\n[![Статус Порога Качества](https://sonar.openbsl.ru/api/project_badges/measure?project=entity\u0026metric=alert_status)](https://sonar.openbsl.ru/dashboard?id=entity)\n[![Рейтинг Сопровождаемости](https://sonar.openbsl.ru/api/project_badges/measure?project=entity\u0026metric=sqale_rating)](https://sonar.openbsl.ru/dashboard?id=entity)\n\nБиблиотека `Entity` предназначена для работы с данными БД как с простыми OneScript объектами. Является реализацией концепции ORM и шаблонов [`DataMapper`](https://martinfowler.com/eaaCatalog/dataMapper.html) и [`ActiveRecord`](https://www.martinfowler.com/eaaCatalog/activeRecord.html) в OneScript. Вдохновение черпается из [Java Persistence API](https://ru.wikipedia.org/wiki/Java_Persistence_API) и [TypeORM](https://github.com/typeorm/typeorm).\n\nВозможности:\n\n* описание таблиц БД в виде специальным образом аннотированных OneScript классов;\n* сохранение объектов OneScript в связанных таблицах БД;\n* поиск по таблицам с результатом в виде коллекции заполненных данными объектов OneScript;\n* абстрактный программный интерфейс (API), не зависящий от используемой СУБД;\n* референсная реализация полнофункционального коннектора к SQLite и PostgreSQL, а так же упрощенного коннектора к файлам JSON.\n\nОписание публичного интерфейса - каталог [docs](docs).\n\n## Оглавление\n\n* \u003ca href=\"#header\"\u003eentity - OneScript Persistence API\u003c/a\u003e\n  * \u003ca href=\"#entity-example\"\u003eПример класса-сущности\u003c/a\u003e\n  * \u003ca href=\"#entity-create\"\u003eСоздание и сохранение сущностей\u003c/a\u003e\n  * \u003ca href=\"#entity-read\"\u003eЧтение и поиск объектов\u003c/a\u003e\n    * \u003ca href=\"#entity-complex-find\"\u003eПоиск сущностей со сложными отборами\u003c/a\u003e\n    * \u003ca href=\"#entity-sort\"\u003eСортировка результатов\u003c/a\u003e\n    * \u003ca href=\"#entity-limit\"\u003eПропуск и смещение\u003c/a\u003e\n  * \u003ca href=\"#entity-delete\"\u003eУдаление сущностей\u003c/a\u003e\n  * \u003ca href=\"#entity-active-record\"\u003eАктивная запись\u003c/a\u003e\n  * \u003ca href=\"#entity-repository\"\u003eРабота через ХранилищеСущностей\u003c/a\u003e\n  * \u003ca href=\"#transactions\"\u003eРабота с транзакциями\u003c/a\u003e\n  * \u003ca href=\"#annotations\"\u003eСистема аннотаций для сущностей\u003c/a\u003e\n    * \u003ca href=\"#annotation-entity\"\u003eСущность\u003c/a\u003e\n    * \u003ca href=\"#annotation-id\"\u003eИдентификатор\u003c/a\u003e\n    * \u003ca href=\"#annotation-generated\"\u003eГенерируемоеЗначение\u003c/a\u003e\n    * \u003ca href=\"#annotation-column\"\u003eКолонка\u003c/a\u003e\n    * \u003ca href=\"#annotation-secondary-table\"\u003eПодчиненнаяТаблица\u003c/a\u003e\n  * \u003ca href=\"#library-structure\"\u003eСтруктура библиотеки\u003c/a\u003e\n    * \u003ca href=\"#library-structure-entity-manager\"\u003eМенеджерСущностей\u003c/a\u003e\n    * \u003ca href=\"#library-structure-entity-repository\"\u003eХранилищеСущностей\u003c/a\u003e\n    * \u003ca href=\"#library-structure-connectors\"\u003eКоннекторы (АбстрактныйКоннектор)\u003c/a\u003e\n    * \u003ca href=\"#library-structure-data-model\"\u003eМодельДанных\u003c/a\u003e\n    * \u003ca href=\"#library-structure-model-object\"\u003eОбъектМодели\u003c/a\u003e\n    * \u003ca href=\"#library-structure-connector-sqlite\"\u003eКоннекторSQLite\u003c/a\u003e\n    * \u003ca href=\"#library-structure-connector-postgresql\"\u003eКоннекторPostgreSQL\u003c/a\u003e\n    * \u003ca href=\"#library-structure-connector-json\"\u003eКоннекторJSON\u003c/a\u003e\n    * \u003ca href=\"#library-structure-connector-inmemory\"\u003eКоннекторInMemory\u003c/a\u003e\n  * \u003ca href=\"#versioning-strategy\"\u003eВерсионирование и обратная совместимость\u003c/a\u003e\n\n\u003ca id=\"entity-example\" /\u003e\n\n## Пример класса-сущности\n\nСущность - это обычный класс OneScript, размеченный служебными аннотациями. Обязательными аннотациями являются `\u0026Сущность` и `\u0026Идентификатор`.\n\nБиблиотека `entity` считывает состав аннотаций класса, строит модель данных и инициализирует таблицы базы данных для работы с объектами данного класса.\n\nОграничения:\n\n* класс-сущность должен иметь конструктор по умолчанию, либо конструктор без параметров, либо конструктор со значениями всех параметров по умолчанию.\n\n```bsl\n// file: СтраныМира.os\n\n// Данный класс содержит данные о странах мира.\n\n\u0026Идентификатор                        // Колонка для хранения ID сущности\nПерем Код Экспорт;                    // Колонка по умолчанию имеет строковый тип\n\nПерем Наименование Экспорт;           // Колонка `Наименование` будет создана в таблице, т.к. поле экспортное.\n\n\u0026Сущность                             // Объект с типом \"СтраныМира\" будет представлен в СУБД как таблица \"СтраныМира\"\nПроцедура ПриСозданииОбъекта()\n\nКонецПроцедуры\n```\n\n```bsl\n// file: Документ.os\n\n\u0026Идентификатор\n\u0026ГенерируемоеЗначение                      // Заполняется автоматически при сохранении сущности\n\u0026Колонка(Тип = \"Целое\")                    // Хранит целочисленные значения\nПерем Идентификатор Экспорт;               // Имя колонки в базе - `Идентификатор`\n\n\u0026Колонка\nПерем Номер Экспорт;                       // Колонка `Номер` будет создана в таблице, т.к. поле экспортное\n\n\u0026Колонка\nПерем Серия Экспорт;                       // Колонка `Номер` будет создана в таблице, т.к. поле экспортное\n\n\u0026Сущность(ИмяТаблицы = \"Документы\")\nПроцедура ПриСозданииОбъекта()             // Объект с типом \"Документ\" будет представлен в СУБД как таблица \"Документы\"\n\nКонецПроцедуры\n```\n\n```bsl\n// file: ФизическоеЛицо.os\n\n// Данный класс содержит информацию о физических лицах.\n\n\u0026Идентификатор                             // Колонка для хранения ID сущности\n\u0026ГенерируемоеЗначение                      // Заполняется автоматически при сохранении сущности\n\u0026Колонка(Тип = \"Целое\")                    // Хранит целочисленные значения\nПерем Идентификатор Экспорт;               // Имя колонки в базе - `Идентификатор`\n\nПерем Имя Экспорт;                         // Колонка `Имя` будет создана в таблице, т.к. поле экспортное.\n\u0026Колонка(Имя = \"Отчество\")                 // Поле `ВтороеИмя` в таблице будет представлено колонкой `Отчество`.\nПерем ВтороеИмя Экспорт;\n\n\u0026Колонка(Тип = \"Дата\")                     // Колонка `ДатаРождения` хранит значения в формате дата-без-времени\nПерем ДатаРождения Экспорт;\n\n\u0026Колонка(Тип = \"Ссылка\", ТипСсылки = \"СтраныМира\")\nПерем Гражданство Экспорт;                 // Данная колонка будет хранить ссылку на класс `СтраныМира`\n\n\u0026ПодчиненнаяТаблица(Тип = \"Массив\", ТипЭлемента = \"Документы\", КаскадноеЧтение = Истина)\nПерем Документы Экспорт;                   // Данное поле будет хранить массив ссылок на класс `Документ`.\n                                           // Для хранения массива будет создана отдельная таблица.\n                                           // Взведенный флаг \"КаскадноеЧтение\" сигнализирует о необходимости\n                                           // инициализировать сущности в массиве при чтении объекта из СУБД.\n\n\u0026Сущность(ИмяТаблицы = \"ФизическиеЛица\")   // Объект с типом `ФизическоеЛицо` (по имени файла) будет представлен в СУБД в виде таблицы `ФизическиеЛица`\nПроцедура ПриСозданииОбъекта()\n\nКонецПроцедуры\n```\n\n\u003ca id=\"entity-create\" /\u003e\n\n## Создание и сохранение сущностей\n\n```bsl\n// Создание менеджера сущностей. Коннектором к базе выступает референсная реализация КоннекторSQLite.\n// В качестве БД используется \"база в оперативной памяти\".\nМенеджерСущностей = Новый МенеджерСущностей(Тип(\"КоннекторSQLite\"), \"FullUri=file::memory:?cache=shared\");\n\n// Создание или обновление таблиц в БД.\nМенеджерСущностей.ДобавитьКлассВМодель(Тип(\"СтраныМира\"));\nМенеджерСущностей.ДобавитьКлассВМодель(Тип(\"Документ\"));\nМенеджерСущностей.ДобавитьКлассВМодель(Тип(\"ФизическоеЛицо\"));\n\n// После заполнения модели менеджер необходимо проинициализировать.\nМенеджерСущностей.Инициализировать();\n\n// Работа с обычными объектом OneScript.\nСохраняемоеФизЛицо = Новый ФизическоеЛицо;\nСохраняемоеФизЛицо.Имя = \"Иван\";\nСохраняемоеФизЛицо.ВтороеИмя = \"Иванович\";\nСохраняемоеФизЛицо.ДатаРождения = Дата(1990, 01, 01);\n\nСтранаМира = Новый СтраныМира;\nСтранаМира.Код = \"643\";\nСтранаМира.Наименование = \"Российская Федерация\";\n\nПаспорт = Новый Документ;\nПаспорт.Номер = \"11 11\";\nПаспорт.Серия = \"111000\";\n\n// Присваиваем колонке с типом \"Ссылка\" конкретный объект с типом \"СтраныМира\"\nСохраняемоеФизЛицо.Гражданство = СтранаМира;\n\n// Инициализируем массив для хранения документов.\n// Это можно сделать и в методе ПриСозданииОбъекта в классе ФизическоеЛицо.os\nСохраняемоеФизЛицо.Документы = Новый Массив;\n// Добавляем новый документ\nСохраняемоеФизЛицо.Документы.Добавить(Паспорт);\n\n// Сохранение объектов в БД\n// Сначала сохраняются подчиненные сущности, потом высокоуровневые\nМенеджерСущностей.Сохранить(СтранаМира);\nМенеджерСущностей.Сохранить(Паспорт);\nМенеджерСущностей.Сохранить(СохраняемоеФизЛицо);\n\n// После сохранения СохраняемоеФизЛицо.Идентификатор содержит автосгенерированный идентификатор.\n// Колонка \"Гражданство\" в СУБД будет хранить идентификатор объекта СтранаМира - значение \"643\".\n// Для хранения документов будет создана отдельная таблица, в которой будут сохранены\n// значения массива с привязкой к физическому лицу.\n```\n\n\u003ca id=\"entity-read\" /\u003e\n\n## Чтение и поиск объектов\n\nДля поиска сущностей существуют методы `Получить()` и `ПолучитьОдно()`.\n\nМетод `Получить()` возвращает массив найденных сущностей.\n\nМетод `ПолучитьОдно()` возвращает одну (первую попавшуюся) сущность или `Неопределено`, если найти сущность не удалось.\n\nОба метода в качестве второго параметра могут принимать в себя условия поиска в следующих видах:\n\n* `Неопределено` (параметр не заполнен) - поиск без отборов;\n* `Соответствие` - пары ИмяПоля-ЗначениеПоля, используемые как отбор по \"равно\";\n* `ОпцииПоиска` - объект типа \"ОпцииПоиска\", позволяющий использовать сложные условия отбора и сортировки.\n\n### Поиск сущностей с простыми отборами\n\n```bsl\n// Для поиска нескольких сущностей, удовлетворяющих условию, можно использовать метод Получить()\n// При вызове метода без параметров будут полученные все сущности указанного типа.\n// В массиве содержатся объекты типа \"ФизическоеЛицо\" с заполненными значениями полей.\n// Поле \"Гражданство\" заполнится готовым объектом с типом \"СтраныМира\".\n// Т.к. над полем \"Документы\" взведен флаг \"КаскадноеЧтение\", то данное поле\n// заполнится массивом с готовыми объектами типа \"Документ\".\n// В обратном случае в массиве содержались бы идентификаторы (ключи) сущностей \"Документ\".\nНайденныеФизЛица = МенеджерСущностей.Получить(Тип(\"ФизическоеЛицо\"));\n\n// В метод Получить() можно передать отбор в виде соответствия\nОтбор = Новый Соответствие;\nОтбор.Вставить(\"Имя\", \"Иван\");\nОтбор.Вставить(\"ВтороеИмя\", \"Иванович\");\n\n// В результирующем массиве окажутся все \"Иваны Ивановичи\", сохраненные в БД.\nНайденныеИваныИванычи = МенеджерСущностей.Получить(Тип(\"ФизическоеЛицо\"), Отбор);\n\n// Допустим в БД сохранено физ. лицо с идентификатором, равным 123.\n// Для получения одной (первой попавшейся) сущности можно использовать метод ПолучитьОдно()\nСохраненноеФизЛицо = МенеджерСущностей.ПолучитьОдно(Тип(\"ФизическоеЛицо\"));\n\n// В метод можно передать отбор в виде соответствия, аналогично методу Получить()\nСохраненноеФизЛицо = МенеджерСущностей.ПолучитьОдно(Тип(\"ФизическоеЛицо\"), Отбор);\n\n// Если вызвать метод \"ПолучитьОдно\" с параметром не-соответствием, то будет осуществлен поиск по идентификатору сущности.\nИдентификатор = 123;\nСохраненноеФизЛицо = МенеджерСущностей.ПолучитьОдно(Тип(\"ФизическоеЛицо\"), Идентификатор);\n```\n\n\u003ca id=\"entity-complex-find\" /\u003e\n\n### Поиск сущностей со сложными отборами\n\n```bsl\n// Найдем всех физических лиц, у которых дата рождения больше, чем 01.01.1990.\nОпцииПоиска = Новый ОпцииПоиска;\nОпцииПоиска.Отбор(\"ДатаРождения\", ВидСравнения.БольшеИлиРавно, Дата(1990, 1, 1));\n\nНайденныеФизЛица = МенеджерСущностей.Получить(Тип(\"ФизическоеЛицо\"), ОпцииПоиска);\n\n// Найдем всех физических лиц, рожденных в 90-ые.\nОпцииПоиска = Новый ОпцииПоиска()\n  .Отбор(\"ДатаРождения\", ВидСравнения.БольшеИлиРавно, Дата(1990, 1, 1))\n  .Отбор(\"ДатаРождения\", ВидСравнения.Меньше, Дата(2000, 1, 1));\n\nДетиДевяностых = МенеджерСущностей.Получить(Тип(\"ФизическоеЛицо\"), ОпцииПоиска);\n\n// Найдем всех физических лиц с именем Иван или Петр.\nМассивИмен = Новый Массив;\nМассивИмен.Добавить(\"Иван\");\nМассивИмен.Добавить(\"Петр\");\n\nОпцииПоиска = Новый ОпцииПоиска()\n  .Отбор(\"Имя\", ВидСравнения.В, МассивИмен);\n\nИваныИПетры = МенеджерСущностей.Получить(Тип(\"ФизическоеЛицо\"), ОпцииПоиска);\n\n// Найдем всех физических лиц НЕ с именем Иван или Петр.\nМассивИмен = Новый Массив;\nМассивИмен.Добавить(\"Иван\");\nМассивИмен.Добавить(\"Петр\");\n\nОпцииПоиска = Новый ОпцииПоиска()\n  .Отбор(\"Имя\", ВидСравнения.НеВ, МассивИмен);\n\nЛюдиСДругимиИменами = МенеджерСущностей.Получить(Тип(\"ФизическоеЛицо\"), ОпцииПоиска);\n```\n\n\u003ca id=\"entity-sort\" /\u003e\n\n### Сортировка результатов\n\n```bsl\n\n// Найдем всех физических лиц, у которых дата рождения больше, чем 01.01.1990\n// и отсортируем результат по дате рождения в порядке убывания.\n\nОпцииПоиска = Новый ОпцииПоиска()\n  .Отбор(\"ДатаРождения\", ВидСравнения.БольшеИлиРавно, Дата(1990, 1, 1))\n  .СортироватьПо(\"ДатаРождения\", НаправлениеСортировки.ПоУбыванию);\n\nДетиДевяностыхПоВозрасту = МенеджерСущностей.Получить(Тип(\"ФизическоеЛицо\"), ОпцииПоиска);\n\n```\n\n\u003ca id=\"#entity-limit\"\u003e\n\n### Пропуск и смещение\n\n```bsl\n\n// Привычный Выбрать Первые Х реализуется через ОпцииПоиска\nОпцииПоиска = Новый ОпцииПоиска()\n  .Первые(10);\n\nПервыеДесятьФизлиц = МенеджерСущностей.Получить(Тип(\"ФизическоеЛицо\"), ОпцииПоиска);\n\n// При желании можно использовать поиск со смещением, например, для реализации постраничной загрузки.\n// Всегда указывайте правила сортировки для повторяемости результата.\nОпцииПоиска = Новый ОпцииПоиска()\n  .Первые(10)\n  .Смещение(50)\n  .СортироватьПо(\"Идентификатор\", НаправлениеСортировки.ПоВозрастанию);\n\nШестойДесятокФизлиц = МенеджерСущностей.Получить(Тип(\"ФизическоеЛицо\"), ОпцииПоиска);\n```\n\n\u003ca id=\"entity-delete\" /\u003e\n\n## Удаление сущностей\n\n```bsl\n// Допустим имеется сущность, которую надо удалить.\n\nМенеджерСущностей.Удалить(СущностьФизическоеЛицо);\n\n// После выполнения метода в БД не останется строки с идентификатором, равным идентификатору сущности\n```\n\n\u003ca id=\"entity-repository\" /\u003e\n\n## Работа через ХранилищеСущностей\n\nДля упрощения взаимодействия с библиотекой помимо МенеджераСущностей, подразумевающего постоянную передачу *типа сущности*, осуществлять операции над сущностями можно через ХранилищеСущностей.  \nХранилище сущностей предоставляет тот же базовый интерфейс, что и МенеджерСущностей, но не требует передачи типа сущности как параметра.\n\n```bsl\n// Получение хранилища сущностей\nХранилищеФизЛиц = МенеджерСущностей.ПолучитьХранилищеСущностей(Тип(\"ФизическоеЛицо\"));\n\n// Поиск сущностей\nИдентификатор = 1;\nФизЛицо = ХранилищеФизЛиц.ПолучитьОдно(Идентификатор);\n\nФизЛицо.Имя = \"Петр\";\n\nХранилищеФизЛиц.Сохранить(ФизЛицо);\n```\n\n\u003ca id=\"entity-active-record\" /\u003e\n\n## Активная запись\n\nДля упрощения работы с сущностями помимо сохранения и удаления сущностей через МенеджерСущностей или ХранилищеСущностей сами объекты сущностей декорируются дополнительными методами `Сохранить`, `Прочитать` и `Удалить`. Все типы сущностей, полученные из Менеджера или Хранилища сущностей с помощью методов `Получить` или `ПолучитьОдно` автоматически декорируются. Для создания нового экземпляра сущности, имеющего дополнительные методы, можно воспользоваться методом `СоздатьЭлемент` у Менеджера или Хранилища сущностей.\n\n```bsl\n// Получение хранилища сущностей.\nХранилищеФизЛиц = МенеджерСущностей.ПолучитьХранилищеСущностей(Тип(\"ФизическоеЛицо\"));\n\n// Создание сущности, обладающей методами \"активной записи\".\nФизЛицо = ХранилищеФизЛиц.СоздатьЭлемент();\nФизЛицо.Идентификатор = 1;\n\n// Чтение данных сущности по текущему идентификатору.\n// Все поля сущности проинициализируются значениями из базы.\nФизЛицо.Прочитать();\n\n// Изменение данных и сохранение через \"активную запись\"\nФизЛицо.Имя = \"Петр\";\nФизЛицо.Сохранить();\n\n// Сущности, полученные из Хранилища сущностей сразу становятся \"активной записью\"\nИдентификатор = 2;\nВтороеФизЛицо = ХранилищеФизЛиц.ПолучитьОдно(Идентификатор);\n\n// И могут быть удалены, через методы \"активной записи\"\nВтороеФизЛицо.Удалить();\n```\n\n\u003ca id=\"transactions\" /\u003e\n\n### Работа с транзакциями\n\nМетоды по работе с транзакциями есть как в Менеджере сущностей, так и в Хранилище сущностей.\n\nТранзакционность поддерживается в рамках экземпляра менеджера сущностей или хранилища сущностей. При необходимости работы с транзакциями с несколькими типами сущностей следует использовать методы работы с транзакциями в Менеджере сущностей и модифицировать сущности через него же.\n\n```bsl\nМенеджерСущностей.НачатьТранзакцию();\n\n// Объекты ФизическоеЛицо и СтранаМира из примеров выше:\nМенеджерСущностей.Сохранить(СтранаМира);\nМенеджерСущностей.Сохранить(СохраняемоеФизЛицо);\n\nМенеджерСущностей.ЗафиксироватьТранзакцию();\n```\n\n\u003ca id=\"annotations\" /\u003e\n\n## Система аннотаций для сущностей\n\nДля связями между классом на OneScript и таблицей в БД используется система аннотаций. Часть аннотаций обязательная к применению. Все параметры аннотаций необязательные.\n\nПри анализе типа сущности менеджер сущностей формирует специальные объекты модели, передаваемые конкретным реализациям коннекторов. Коннекторы могут рассчитывать на наличие всех описанных параметров аннотаций в объекте модели.\n\n\u003ca id=\"annotation-entity\" /\u003e\n\n### Сущность\n\n\u003e Применение: обязательно\n\nКаждый класс, подключаемый к менеджеру сущностей должен иметь аннотацию `Сущность`, расположенную над любым методом класса.\n\nПри отсутствии у класса методов рекомендуется навешивать аннотацию над методом `ПриСозданииОбъекта()`.\n\nАннотация `Сущность` имеет следующие параметры:\n\n* `ИмяТаблицы` - Строка - Имя таблицы, используемой коннектором к СУБД при работе с сущностью. Значение по умолчанию - строковое представление имени типа сценария. При подключении сценариев стандартным загрузчиком библиотек совпадает с именем файла.\n* `ИсточникДанных` - Строка - Повторяемый. Имя источника данных, используемого коннектором к СУБД при работе с сущностью. Если не задано, считается, что сущность может быть использована с любым источником данных.\n\n\u003ca id=\"annotation-id\" /\u003e\n\n### Идентификатор\n\n\u003e Применение: обязательно\n\nКаждый класс, подключаемый к менеджеру сущностей, должен иметь поле для хранения идентификатора объекта в СУБД - первичного ключа. Для формирования автоинкрементного первичного ключа можно воспользоваться дополнительной аннотацией `ГенерируемоеЗначение`.\n\nАннотация `Идентификатор` не имеет параметров.\n\n\u003ca id=\"annotation-generated\" /\u003e\n\n### ГенерируемоеЗначение\n\n\u003e Применение: необязательно\n\nДля части полей допустимо высчитывать значение колонки при вставке записи в таблицу. Например, для первичных числовых ключей обычно не требуется явное управление назначаемыми идентификаторами.\n\nРеференсная реализация коннектора на базе SQLite поддерживает единственный тип генератора значений - `AUTOINCREMENT`.\n\n\u003e Планируется расширение аннотации указанием параметров генератора.\n\nАннотация `ГенерируемоеЗначение` не имеет параметров.\n\n\u003ca id=\"annotation-column\" /\u003e\n\n### Колонка\n\n\u003e Применение: необязательно\n\nВсе **экспортные** поля класса (за исключением полей, помеченных аннотаций `ПодчиненнаяТаблица`) преобразуются в колонки таблицы в СУБД. Аннотация `Колонка` позволяет тонко настроить параметры колонки таблицы.\n\nАннотация `Колонка` имеет следующие параметры:\n\n* `Имя` - Строка - Имя колонки, используемой коннектором к СУБД при работе с сущностью. Значение по умолчанию - имя свойства.\n* `Тип` - ТипыКолонок - Тип колонки, используемой для хранения идентификатора. Значение по умолчанию - `ТипыКолонок.Строка`. Доступные типы колонок:\n  * Целое\n  * Дробное\n  * Булево\n  * Строка\n  * Дата\n  * Время\n  * ДатаВремя\n  * Ссылка\n  * ДвоичныеДанные\n* `ТипСсылки` - Строка - Имя зарегистрированного в модели типа, в который преобразуется значение из колонки. Имеет смысл только в паре с параметром `Тип`, равным `Ссылка`. Допустимо указывать примитивные типы из перечисления `ТипыКолонок` и типы сущностей (например, `\"ФизическоеЛицо\"`)\n\n\u003ca id=\"annotation-secondary-table\" /\u003e\n\n### ПодчиненнаяТаблица\n\n\u003e Применение: необязательно\n\nАннотация `ПодчиненнаяТаблица` используется для хранения коллекций - массивов и структур.\n\nАннотация `ПодчиненнаяТаблица` имеет следующие параметры:\n\n* `ИмяТаблицы` - Строка - Имя таблицы, используемой коннектором к СУБД при работе с сущностью. Значение по умолчанию - строка вида `ИмяТаблицыСущности_ИмяСвойства`.\n* `Тип` - ТипыПодчиненныхТаблиц - Тип колонки, используемой для хранения идентификатора. Доступные типы подчиненных таблиц:\n  * Массив\n  * Структура\n* `ТипЭлемента` - Строка - Имя зарегистрированного в модели типа, в который преобразуется значение из колонки. Допустимо указывать примитивные типы из перечисления `ТипыКолонок` и типы сущностей (например, `\"ФизическоеЛицо\"`).\n* `КаскадноеЧтение` - Булево - Флаг, отвечающий за инициализацию сущностей в подчиненной таблице (если `ТипЭлемента` является ссылочным типом).\n\n\u003ca id=\"library-structure\" /\u003e\n\n## Структура библиотеки\n\nОписание публичного интерфейса - каталог [docs](docs).\n\n\u003ca id=\"library-structure-entity-manager\" /\u003e\n\n### МенеджерСущностей\n\nМенеджерСущностей предоставляет публичный интерфейс по чтению, сохранению, удалению данных. МенеджерСущностей инициализируется конкретным типом *коннектора* к используемой базе данных. Все операции по изменению данных МенеджерСущностей делегирует Коннектору. В зоне ответственности МенеджераСущностей находятся:\n\n* Создание и наполнение МоделиДанных\n* Трансляция запросов от прикладной логики к коннекторам\n* Конструирование найденных сущностей по данным, возвращаемым коннекторами\n\n\u003ca id=\"library-structure-entity-repository\" /\u003e\n\n### ХранилищеСущностей\n\nХранилищеСущностей предоставляет тот же интерфейс по работе с сущностями и транзакциями, но с глобальной привязкой к конкретному типу сущности. Для получения ХранилищаСущностей служит метод `МенеджерСущностей::ПолучитьХранилищеСущностей`.\n\nВ отличие от МенеджераСущностей, ХранилищеСущностей не требует передачи в методы параметра \"ТипСущности\".\n\nХранилища сущностей и пулы сущностей совпадают в рамках одного типа сущности, типа коннектора и строки соединения. Другими словами, два менеджера сущности, инициализированные одним и тем же коннектором и строкой соединения, вернут одинаковые хранилища сущностей одного типа.\n\n\u003ca id=\"library-structure-connectors\" /\u003e\n\n### Коннекторы (АбстрактныйКоннектор)\n\nКоннектор содержит в себе логику по работе с конкретной СУБД. Например, `КоннекторSQLite` служит для оперирования СУБД SQLite. В зоне ответственности коннектора находятся:\n\n* подключение к СУБД\n* работа с транзакциями\n* инициализация таблиц базы данных;\n* CRUD-операции над таблицами, в которых хранятся сущности (создание-получение-обновление-удаление);\n* преобразование типов по данным ОбъектаМодели в типы колонок СУБД.\n\nКо всем коннекторам предъявляются определенные требования:\n\n* каждый коннектор **обязан** реализовывать интерфейс, представленный в классе [`АбстрактныйКоннектор`](https://github.com/nixel2007/entity/blob/develop/src/%D0%9A%D0%BB%D0%B0%D1%81%D1%81%D1%8B/%D0%90%D0%B1%D1%81%D1%82%D1%80%D0%B0%D0%BA%D1%82%D0%BD%D1%8B%D0%B9%D0%9A%D0%BE%D0%BD%D0%BD%D0%B5%D0%BA%D1%82%D0%BE%D1%80.os);\n* коннектор **может** писать предупреждающие сообщения или выдавать исключения на методах, которые он не поддерживает или поддерживает не полностью.\n\nНапример, `КоннекторJSON` не умеет работать с транзакциями, однако, он имеет соответствующие методы, выводящие диагностические сообщения при их вызове.\n\n\u003e Важно!\n\nКаждое ХранилищеСущностей и МенеджерСущностей хранят в себе отдельные экземпляры Коннекторов. Тип, строка соединения и параметры коннектора определяются при создании МенеджераСущностей.\n\n\u003ca id=\"library-structure-data-model\" /\u003e\n\n### МодельДанных\n\nМодель данных хранит в себе список всех зарегистрированных классов-сущности в виде ОбъектовМодели\n\n\u003ca id=\"library-structure-model-object\" /\u003e\n\n### ОбъектМодели\n\nОбъектМодели хранит детальную мета-информацию о классе сущности, его полях и данных всех аннотаций. Из ОбъектаМодели можно получить:\n\n* тип сущности;\n* имя таблицы для хранения сущности;\n* список всех колонок, с информацией о:\n  * имени поля класса;\n  * имени колонки в БД;\n  * типе колонки в БД;\n  * типе элемента (в случае ссылочного типа колонки);\n  * значения флага \"Идентификатор\";\n  * значения флага \"ГенерируемоеЗначение\";\n* список подчиненных таблиц с информацией о:\n  * имени поля класса\n  * имени таблицы в БД\n  * типе подчиненной таблицы\n  * типе элемента\n* ссылку на данные колонки-идентификатора.\n\nПомимо мета-информации ОбъектМодели позволяет получать значения колонок таблицы на основании имен полей сущности (и наоборот), вычислять значение идентификатора сущности, выполнять приведение типов и установку значений полей сущности.\n\n\u003ca id=\"library-structure-connector-sqlite\" /\u003e\n\n### КоннекторSQLite\n\nВ состав библиотеки входит референсная реализация интерфейса коннектора в виде коннектора к СУБД SQLite. Реализация базируется на библиотеке [sql](https://github.com/oscript-library/sql), есть поддержка работы в OneScript.Web.\n\nКоннектор SQLite поддерживает все CRUD-операции над сущностями, простой и сложный поиск, работу с транзакциями.\n\n\u003e Внимание!\n\nПри использовании in-memory базы данных в моделях больше, чем с одним типом сущности, строка соединения должна выглядеть так: `\"FullUri=file::memory:?cache=shared\"`\n\n\u003ca id=\"library-structure-connector-postgresql\" /\u003e\n\n### КоннекторPostgreSQL\n\nВ состав библиотеки входит референсная реализация интерфейса коннектора в виде коннектора к СУБД PostgreSQL. Реализация базируется на библиотеке [sql](https://github.com/oscript-library/sql), есть поддержка работы в OneScript.Web.\n\nКоннектор PostgreSQL поддерживает все CRUD-операции над сущностями, простой и сложный поиск, работу с транзакциями.\n\n\u003ca id=\"library-structure-connector-json\" /\u003e\n\n### КоннекторJSON\n\nВ состав библиотеки входит референсная реализация интерфейса коннектора в виде упрощенного коннектора к набору файлов JSON. Каждая таблица хранится в отдельном файле в формате JSON в виде пар Ключ-Значение, где ключом выступает идентификатор сущности, а значением - сериализованная в JSON-объект сущность.\n\nВ качестве строки соединения указывается путь к каталогу, в котором будут сохранены файлы.\n\nКоннектор SQLite поддерживает все CRUD-операции над сущностями, простой и сложный поиск, но не поддерживает работу с транзакциями. При вызове операций по работе с транзакциями будут выданы исключения.\n\nВсе операциями по записи и удалению сущностей одного типа проводятся **синхронно**, блокируя файл таблицы целиком. Для контроля над синхронным доступом используется библиотека [semaphore](https://github.com/nixel2007/semaphore).\n\n\u003ca id=\"library-structure-connector-inmemory\" /\u003e\n\n### КоннекторInMemory\n\nВ состав библиотеки входит референсная реализация интерфейса коннектора в виде упрощенного коннектора к виртуальной базе данных в памяти. База данных состоит из соответствия, где ключ - имя таблицы модели данных, значение таблицы.\n\nВ качестве строки соединения произвольная строка, которая будет являться разделителем данных.\n\nКоннектор поддерживает все CRUD-операции над сущностями, простой и сложный поиск, но не поддерживает работу с транзакциями. При вызове операций по работе с транзакциями будут выданы исключения.\n\n\u003ca id=\"versioning-strategy\" /\u003e\n\n## Версионирование и обратная совместимость\n\nБиблиотека `entity` в целом следует концепции [семантического версионирования](https://semver.org/) со следующими изменениями в правилах нумерации версий:\n\n* первая цифра версии - Major.Entity - версия API Менеджера сущностей;\n* вторая цифра версии - Major.Connector - версия API Коннекторов;\n* третья цифра версии - Minor - новая функциональность в рамках мажорных версий;\n* четвертая цифра версии - Patch - исправление ошибок.\n\nТаким образом:\n\n* прикладное ПО может быть уверено в сохранении обратной совместимости в рамках первой цифры версии;\n* коннекторы к СУБД могут быть уверены в сохранении обратной совместимости и требований по реализации API в рамках второй цифры версии, невзирая на значение первой цифры.\n\nПод контроль и обязательство соблюдения обратной совместимости попадают:\n\n* для Major.Entity:\n  * все публичные непомеченные как \"нестабильные\" (`@unstable`) или \"для служебного использования\" (`@internal`) методы классов:\n    * [`МенеджерСущностей`](src/Классы/МенеджерСущностей.os),\n    * [`ХранилищеСущностей`](src/Классы/ХранилищеСущностей.os),\n    * [`ОпцииПоиска`](src/Классы/ОпцииПоиска.os),\n    * [`МодельДанных`](src/Классы/МодельДанных.os),\n    * [`ОбъектМодели`](src/Классы/ОбъектМодели.os),\n    * [`ЭлементОтбора`](src/Классы/ЭлементОтбора.os);\n    * [`ЭлементПорядка`](src/Классы/ЭлементПорядка.os);\n  * значения модулей-перечислений:\n    * [`ТипыКолонок`](src/Модули/ТипыКолонок.os),\n    * [`ТипыПодчиненныхТаблиц`](src/Модули/ТипыПодчиненныхТаблиц.os),\n    * [`ВидСравнения`](src/Модули/ВидСравнения.os);\n  * состав и параметры аннотаций сущностей;\n  * методы [\"активной записи\"](docs/АктивнаяЗапись.md) сущности;\n* для Major.Connector:\n  * все публичные методы класса [`АбстрактныйКоннектор`](src/Классы/АбстрактныйКоннектор.os) и их сигнатуры;\n  * все публичные непомеченные как \"нестабильные\" (`@unstable`) методы классов:\n    * [`МодельДанных`](src/Классы/МодельДанных.os),\n    * [`ОбъектМодели`](src/Классы/ОбъектМодели.os),\n    * [`ОпцииПоиска`](src/Классы/ОпцииПоиска.os),\n    * [`ЭлементОтбора`](src/Классы/ЭлементОтбора.os);\n    * [`ЭлементПорядка`](src/Классы/ЭлементПорядка.os);\n  * значения модулей-перечислений:\n    * [`ТипыКолонок`](src/Модули/ТипыКолонок.os),\n    * [`ТипыПодчиненныхТаблиц`](src/Модули/ТипыПодчиненныхТаблиц.os),\n    * [`ВидСравнения`](src/Модули/ВидСравнения.os).\n\n\u003e To be continued...\n","funding_links":["https://t.me/tribute/app?startapp=sdzj","https://t.me/tribute/app?startapp=d7Rs","https://github.com/sponsors/nixel2007","https://ko-fi.com/nixel2007","https://patreon.com/nixel2007"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnixel2007%2Fentity","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnixel2007%2Fentity","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnixel2007%2Fentity/lists"}