Добавление данных в две таблицы (ZeosLib)

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

Добавление данных в две таблицы (ZeosLib)

Сообщение Unvictis » 27.11.2021 21:25:06

Здравствуйте ребята!

Пишу простенькую БД и приложение к ней для инвентаризации компьютеров предприятия (Lazarus 2.0.8 x86, ZeosLib 7.2.14, SQLite3 3.36.0, Windows 10 x64). В ней имеются две таблички "Parts" (Оборудование) и "Journal" (Журнал). В первой содержится перечень оборудования, во второй события, произошедшие с ним (отношение "один ко многим"). В табличке "Journal" есть внешний ключ на записи из "Parts" (PN). Для доступа к табличкам использую компоненты TZTable (ZeosLib). Сейчас работаю над диалогом добавления оборудования или изменения сведений об оборудовании (см. скриншоты).

Хочу реализовать такую логику: при добавлении нового оборудования или изменении информации о старом сначала в таблицу "Parts" добавляется / редактируется запись об оборудовании. Потом в таблицу "Journal" добавляется запись, где пользователь пишет, почему он произвёл добавление / изменение информации. Тоесть при показе данного диалога я пишу:

Код: Выделить всё
..
ztParts.Insert;
ztJournal.Insert;
..


Однако, при переключении с одного DB-Aware компонента, привязанного к ztParts на другой, привязанный к ztJournal и наоборот один из датасетов переходит из режима dsInsert в режим dsBrowse, из за чего например элементах управления привязанных к "Journal" отображаются данные от другой записи. Пока "победил" такое поведение так (в данном случае, при вставке новой записи):

Код: Выделить всё
ztParts.Insert;
ztParts.Post;
ztJournal.Insert;
ztJournal.Post;
ztParts.Edit;


При переключении вкладок PageControl'a (Оборудование / Журнал) вызываю метод Edit соответствующего TZTable. А потом, при закрытии диалога дабы связать запись об оборудовании с записью в журнале ещё и:

Код: Выделить всё
ztParts.ApplyUpdates;

ztJournal.Edit;
ztJournal.FieldByName('PN').AsInteger :=
ztParts.FieldByName('PartID').AsInteger;

ztJournal.Post;
ztJournal.ApplyUpdates;


Но чувствую что всё это сплошные костыли и быдлокодерство. Не говоря уже о том, что из-за постоянного быстрого переключения DB-aware компонентов в разные режимы, диалог вставки/редактирования при запуске ощутимо подтормаживает. В связи с этим, основной мой вопрос: каким образом правильно вставить связанные записи в две таблицы? Какими компонентами для этого лучше воспользоваться (TZTable / TZQuery + TZUpdateSQL)? Для краткости приведу алгоритм действий для добавления.

Добавление оборудования:

  • Вставка новой записи в таблицу Parts
  • Редактирование только что созданной записи
  • Добавление новой записи в таблицу Journal
  • Редактирование новой записи в таблице Journal
  • Присвоение внешнего ключа записи из таблицы Journal от новой записи таблицы Parts
  • Фиксация (COMMIT) или отмена (ROLLBACK) изменений, в зависимости от того, какую кнопку нажмёт пользователь.

Прошу прощения за длинный пост, и благодарю за внимание!

Скриншоты:
Изображение Изображение
Аватара пользователя
Unvictis
новенький
 
Сообщения: 48
Зарегистрирован: 17.07.2015 18:59:12
Откуда: Kokshetau, Kazakshtan

Re: Добавление данных в две таблицы (ZeosLib)

Сообщение DedFrend » 27.11.2021 23:49:03

Вообще-то общее правило в таких случаях:
1)Таблица Journal д.б. Detail для Part. То есть поле Mastersource таблицы Journal должно быть ссылкой на Datasource таблицы Part.
2) При добавлении записи в Part можно автоматически добавлять запись в Journal. Но делать это нужно только именно при вставке
новой записи в Part. Лучше всего это делать в AfterPost, чтобы запись в Part уже была. Можно занести в "Основание" что-то типа
"Взято на учет".
3) При добавлении записи в Journal ссылка на Part добавится автоматом. Остальные ключи надо делать самому в OnNewRecord
4) "Вручную" делать Insert/Edit/Update обычно не надо. Исключение - случай описанный в пункте 2

Вы упоминаете Commit/Rollback . Если у вас серверная СУБД, то еще можно огрести массу приключений на транзакциях. Но если вам
реально нужен многопользовательский доступ к базе - то выбора нет.
DedFrend
постоялец
 
Сообщения: 156
Зарегистрирован: 25.11.2018 12:21:50

Re: Добавление данных в две таблицы (ZeosLib)

Сообщение Unvictis » 28.11.2021 09:57:02

DedFrend писал(а):2) При добавлении записи в Part можно автоматически добавлять запись в Journal. Но делать это нужно только именно при вставке
новой записи в Part. Лучше всего это делать в AfterPost, чтобы запись в Part уже была. Можно занести в "Основание" что-то типа
"Взято на учет".

Большое спасибо за быстрый ответ! Однако, я хотел реализовать возможность одновременного редактирования обоих записей, тоесть либо сразу же обе записи добавляются, либо не добавляется ни одна. Тоесть человек заполнил данные об оборудовании, написал почему он его добавляет в журнал на второй вкладке, а потом решил тут-же внести снова некоторые правки в запись об оборудовании.

Пока нашёл ещё один способ оптимизировать мой код, перед вставкой записей использовать TDataSet.DisableControls, ну и для начальной вставки "пустых" записей (что-бы записи присвоился AUTOINCREMENT) использовать InsertRecord. Буду пробовать сначала их.
Аватара пользователя
Unvictis
новенький
 
Сообщения: 48
Зарегистрирован: 17.07.2015 18:59:12
Откуда: Kokshetau, Kazakshtan

Re: Добавление данных в две таблицы (ZeosLib)

Сообщение DedFrend » 28.11.2021 12:36:52

Принципиально неправильно ВСЕГДА вставлять две записи. Тогда это должна быть одна таблица и не надо голову морочить.
С другой стороны - никто не мешает редактировать уже существующую запись Part. Нельзя только трогать ключевые поля.
А добавлять в Part разные записи на одно оборудование - это и организационно неправильно
DedFrend
постоялец
 
Сообщения: 156
Зарегистрирован: 25.11.2018 12:21:50

Re: Добавление данных в две таблицы (ZeosLib)

Сообщение Unvictis » 28.11.2021 17:24:31

DedFrend писал(а):Принципиально неправильно ВСЕГДА вставлять две записи. Тогда это должна быть одна таблица и не надо голову морочить.
С другой стороны - никто не мешает редактировать уже существующую запись Part. Нельзя только трогать ключевые поля.
А добавлять в Part разные записи на одно оборудование - это и организационно неправильно

В целом, я согласен с вами. Но вот вопрос, как же это реализовать? Возможно стоит использовать TZQuery, TZQuery + TZUpdateSQL? Вызывать отдельную транзакцию, вставлять записи, а потом по очереди их редактировать? Никак не соображу, как это сделать на практике.
Аватара пользователя
Unvictis
новенький
 
Сообщения: 48
Зарегистрирован: 17.07.2015 18:59:12
Откуда: Kokshetau, Kazakshtan

Re: Добавление данных в две таблицы (ZeosLib)

Сообщение DedFrend » 28.11.2021 19:36:26

По идее, две TZTable для Part и Journal, по DataSource, DBGrid и Navigator к ним и все должно работать само. По Ok Commit, по Cancel - Rollback. Если
хочется, можно специальные кнопки.
Связка TZQuery + TZUpdateSQL для более сложных случаев. Когда результат редактирования одной записи должен сохраняться в разных таблицах.
Поскольку, видимо, впервые делаете, рекомендую сделать тестовый пример: БД из двух таблиц, одна главная, другая Detail - имеет поле-ссылку на главную.
У Detail MasterSource указывает на главную. Повставляйте записи, поредактируйте. При переходе по мастер таблице должны в Detail отображаться только с
тем же значением внешнего ключа. Подобных примеров в учебниках и интернете - как грязи
DedFrend
постоялец
 
Сообщения: 156
Зарегистрирован: 25.11.2018 12:21:50

Re: Добавление данных в две таблицы (ZeosLib)

Сообщение alexs » 29.11.2021 09:31:19

Unvictis
В обычных ситуациях, как уже писали, редко возникает потребность редактирвания записей из сразу двух таблиц. Если это массовое явление - то скорее всего есть ошибки в проектирование данных.
Для исключительных случаев можно обойти через хранимые процедуры. Т.е. данные выбираются в приложение в Query - а редактирование этого набора идёт через UpdateSQL. В тексте запроса на редактирование указывается вызова хранимой процедуры. А в самой процедуре уже распихиваются данных по необходимым таблицам.
Этим самым обечпецивается атомарность факта редактирования - уменьшается вероятность "зависших" транзакций. Минимизируется трафик. Но в, какой-то мере, усложняется поддержка.
Аватара пользователя
alexs
долгожитель
 
Сообщения: 4053
Зарегистрирован: 15.05.2005 23:17:07
Откуда: г.Ставрополь

Re: Добавление данных в две таблицы (ZeosLib)

Сообщение Снег Север » 29.11.2021 10:37:43

alexs, автор использует SQLite, т.е. приложение однопользовательское. Там всё упрощается. Никаких проблем с трафиком, целостности транзакций нет. Вот если бы это была серверная база данных - тогда да.
Аватара пользователя
Снег Север
долгожитель
 
Сообщения: 2995
Зарегистрирован: 27.11.2007 16:14:47

Re: Добавление данных в две таблицы (ZeosLib)

Сообщение Unvictis » 29.11.2021 11:30:13

Спасибо за ответы! А как вообще в ZeosLib устроена работа с транзакциями? Только через компонент TZConnection? Т. е. что-бы запустить ещё одну транзакцию мне нужно добавлять ещё один компонент TZConnection?

Добавлено спустя 2 часа 23 минуты 44 секунды:
И ещё, можно ли сделать TZQuery, который ничего не выбирает, но в который можно вставлять данные в таблицу?
Аватара пользователя
Unvictis
новенький
 
Сообщения: 48
Зарегистрирован: 17.07.2015 18:59:12
Откуда: Kokshetau, Kazakshtan

Re: Добавление данных в две таблицы (ZeosLib)

Сообщение Снег Север » 29.11.2021 16:54:02

Unvictis, Query для вставки/изменения данных - самая распространенная вещь. Конкретно про Zeos не знаю, но обычно для выполнения используется свойство с названием типа ExecSQL.
Аватара пользователя
Снег Север
долгожитель
 
Сообщения: 2995
Зарегистрирован: 27.11.2007 16:14:47

Re: Добавление данных в две таблицы (ZeosLib)

Сообщение Unvictis » 29.11.2021 17:02:38

Снег Север писал(а):Unvictis, Query для вставки/изменения данных - самая распространенная вещь. Конкретно про Zeos не знаю, но обычно для выполнения используется свойство с названием типа ExecSQL.

Ну в смысле, вставить данные, а потом сразу же приступить к их редактированию в DB-Aware компонентах.
Аватара пользователя
Unvictis
новенький
 
Сообщения: 48
Зарегистрирован: 17.07.2015 18:59:12
Откуда: Kokshetau, Kazakshtan

Re: Добавление данных в две таблицы (ZeosLib)

Сообщение Снег Север » 29.11.2021 22:55:27

Unvictis, последовательность действий - вставляете данные SQL-запросом insert..., командуете коммит, потом в датасете, связанным с DB-Aware компонентами, делаете рефреш - вуаля, ваши данные обновились! :D
Аватара пользователя
Снег Север
долгожитель
 
Сообщения: 2995
Зарегистрирован: 27.11.2007 16:14:47

Re: Добавление данных в две таблицы (ZeosLib)

Сообщение DedFrend » 30.11.2021 00:26:52

Это распространенное заблуждение, что для вставки записей нужны запросы. TZTable+TDatasource вам в руки и НИЧЕГО (впрочем, кроме назначения ключа) руками делать не надо будет.
На навигаторе нажимаете плюсик - вставляется запись. В OnNewRecord присваиваете значение ключу. Обычно с помощью генератора. Остальные поля заполняете
с клавы в компонентах со страницы Data Controls
DedFrend
постоялец
 
Сообщения: 156
Зарегистрирован: 25.11.2018 12:21:50

Re: Добавление данных в две таблицы (ZeosLib)

Сообщение Снег Север » 30.11.2021 09:03:29

DedFrend, такое годится для самых примитивных случаев только. В моей практике, при создании новой записи, в неё часто надо было сразу добавлять некоторые данные. Например, время создания, некоторые данные по умолчанию и пр. Конечно, это можно делать триггером или встроенной процедурой. Но проще - запросом из программы.
Аватара пользователя
Снег Север
долгожитель
 
Сообщения: 2995
Зарегистрирован: 27.11.2007 16:14:47

Re: Добавление данных в две таблицы (ZeosLib)

Сообщение alexs » 30.11.2021 11:06:33

DedFrend писал(а):TZTable+TDatasource вам в руки

Самый быстрый и самый плохой вариант
На таблицах > 1000 строк уже не приемлем.
Запросы хороши именно тем, что позволяют чётко ограничивать набор данных по разным критериям. Ну и визуализация через соедиение основных таблиц и справочников - это тоже одна из самых важных функций.
Снег Север писал(а):Но проще - запросом из программы.

Постгрес даёт такую класную вешь как универсальный тригер. У меня в каждой таблице есть стандартный набор полей, отвечающих за протоколирование - и на всех таблицах есть один и тот же триггер. Очень удобно.
Аватара пользователя
alexs
долгожитель
 
Сообщения: 4053
Зарегистрирован: 15.05.2005 23:17:07
Откуда: г.Ставрополь

След.

Вернуться в Lazarus

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 29

Рейтинг@Mail.ru