Редактирование таблицы БД с уникальной комбинацией полей |
Здравствуйте, гость ( Вход | Регистрация )
Редактирование таблицы БД с уникальной комбинацией полей |
Steklova Olga |
28.5.2013, 16:48
Сообщение
#1
|
Участник Группа: Участник Сообщений: 198 Регистрация: 27.9.2011 Из: Санкт-Петербург Пользователь №: 2912 Спасибо сказали: 5 раз(а) Репутация: 4 |
Всем привет Прошу не бить за многословие
Я до сих пор редактировала таблицы с экрана только в том случае, когда надо было пометить какие-то записи. Для этого наследовала модель от QSqlTableModel, выставляла в flags для нужной колонки Qt::ItemIsUserCheckable, переопределяла setData и т.д. А сейчас надо редактировать почти все поля таблиц. К тому же, значения некоторых полей должны составлять уникальную комбинацию, но быть при этом редактируемыми. Не подскажете, как проще сделать такое редактирование? Подробнее... У меня есть штук 15 вью, к каждому привязана своя модель с таблицей БД. Вью расположены на страницах блокнота. На каждой странице - какая-то главная таблица и ее подчиненные. Таблицы, например, такие:
Поля F_PK, F_V во вью скрыты, остальные видны. У модели стоит фильтр F_V = 0. Алгоритм предусматривает, что оператор может редактировать поля F_A, F_B, F_C, F_D, F1, F2.
В таблице T_OBJ можно "безобидно" отредактировать только поля F1, F2. А поля F_A, F_B, F_C, F_D надо редактировать только в совокупности. Например, в таблице есть записи: F_PK=1 F_A=1 F_B=1 F_C=1 F_D=1 F1=1 F2=1 F_PK=2 F_A=2 F_B=1 F_C=1 F_D=1 F1=1 F2=1 Если в записи с F_PK=1 надо поменять F_A=1 F_B=1 на F_A=2 F_B=2, то нельзя после изменения F_A с 1 на 2 сразу подтвердить это частичное изменение записи, а потом поменять F_B с 1 на 2 и подтвердить изменение. Иначе нарушится уникальность комбинации полей F_A, F_B, F_C, F_D в таблице. После редактирования всех полей записи, которые надо поменять, надо как-то сообщить программе, что оператор закончил редактирование конкретной записи. Тогда программа должна проверить, правомерно ли такое редактирование записи (не нарушает ли оно уникальную комбинацию полей), если правомерно - то подтвердить редактирование и запомнить изменения в БД. К тому же, программа должна в соответствии с тем, какие из полей F_A, F_B, F_C, F_D поменяли свои значения, произвести дополнительное программное редактирование некоторых таблиц БД. Как сделать редактирование таких таблиц прямо в QTableView, я не понимаю... К сожалению, никогда не видела подобного работающего примера. Мешает уникальная комбинация полей. Или я не так спроектировала структуру таблиц? И еще, надо ли делать уникальный ключ для группы полей F_A, F_B, F_C, F_D? С ключом будет лучше? Может быть, сделать так... Сделать одну панель с тремя кнопками (Добавить, Изменить, Удалить). Слева на экране отобразить блокнот с таблицами, справа выделить область для редактирования данных. При нажатии кнопки Изменить, начать редактирование текущей записи таблицы, которая перед этим была в фокусе. Для этого в области справа отобразить, в соответствии с типом поля, разные LineEdit, ComboBox, SpinBox, в которые занести данные из текущей записи. После редактирования всех полей записи, которые надо поменять, нажать кнопку "Редактирование записи завершено", при этом проверить уникальность, если все хорошо, то запомнить изменения в БД, произвести дополнительное программное редактирование некоторых таблиц БД. Вопрос: эти LineEdit, ComboBox, SpinBox можно добавлять к мапперу QDataWidgetMapper? Или нельзя из-за уникальной комбинации полей? Есть еще вариант - вместо выделения области для редактирования в основном окне открывать окно редактирования текущей записи как диалог... Вообще-то, вариант редактирования записей в другой области экрана, а не в самом TableView, мне не нравится вот чем. Мне кажется, надо делать так, чтобы оператор редактировал все таблицы БД по одному алгоритму. (А не так, что одни таблицы редактируюся в отдельной области, а другие в самом вью.) А в большинстве подчиненных таблиц у меня редактируется только одно поле (например, в таблице T_OBJ_FR). Не хочется для ввода одного значения заставлять оператора переключаться в область редактирования справа... Но, зато этот вариант мне кажется намного проще запрограммировать. Спасибо Сообщение отредактировал Steklova Olga - 29.5.2013, 8:16 |
|
|
Litkevich Yuriy |
28.5.2013, 19:17
Сообщение
#2
|
разработчик РЭА Группа: Сомодератор Сообщений: 9669 Регистрация: 9.1.2008 Из: Тюмень Пользователь №: 64 Спасибо сказали: 807 раз(а) Репутация: 94 |
И еще, надо ли делать уникальный ключ для группы полей F_A, F_B, F_C, F_D? С ключом будет лучше? нельзя делать, т.к. оператор может захотеть (понадобится) изменить две записи на противоположные, при фиксации изменений в БД, БД будет "позаписьно" пытаться применить изменения - возникнет конфликт, транзакцию завершить не удастся.Фиксировать данные в БД нужно вручную (ManualSubmit). на модель можно вешать "тригеры" (например, beforeUpdate) в "тригерах" и обрабатывай проверку на уникальность. Правда тут нужно подумать что делать если условие не соблюдено. Самое простое - вернуть всё назад, но это начнёт бесить оператора (его ошибка может быть очень маленькой, а изменения которые ему придётся повторить - очень большие). Сложнее - сигналить из модели об ошибке, показывать суть ошибки оператору, принудительно переводить делегата (одного из) в режим редактирования. |
|
|
Iron Bug |
29.5.2013, 7:29
Сообщение
#3
|
Профессионал Группа: Модератор Сообщений: 1611 Регистрация: 6.2.2009 Из: Yekaterinburg Пользователь №: 533 Спасибо сказали: 219 раз(а) Репутация: 12 |
это начнёт бесить оператора (его ошибка может быть очень маленькой, а изменения которые ему придётся повторить - очень большие). в этом и есть проблема. пользователь делает всё последовательно. он не может менять две записи параллельно. сначала он правит одну, потом - другую. в момент где-то посередине изменений текущее состояние может не соответствовать уникальности. но если начать сразу предпринимать какие-то действия, то юзера это точно будет бесить. лучше так не делать. проверять нужно перед завершением транзакции, вручную. и предупреждать пользователя об ошибках, а не откатывать сразу всё. |
|
|
Steklova Olga |
29.5.2013, 9:40
Сообщение
#4
|
Участник Группа: Участник Сообщений: 198 Регистрация: 27.9.2011 Из: Санкт-Петербург Пользователь №: 2912 Спасибо сказали: 5 раз(а) Репутация: 4 |
Цитата(Litkevich Yuriy) оператор может захотеть (понадобится) изменить две записи на противоположные Я собиралась вносить изменения в БД сразу после редактирования очередной записи, но еще не придумала, какие варианты решения предлагать оператору, если возникнет нарушение уникальности. И не собиралась разрешать оператору изменять две записи на противоположные. Хотя, наверное, я соглашусь с вами, что не надо издеваться над оператором, надо разрешить менять несколько записей, как ему захочется, и только после этого нажимать кнопку подтверждения внесенных изменений. Главное, чтобы оператор не забывал ее нажимать. А в целом мне остается совершенно неясно, как запрограммировать корректировку таблиц. |
|
|
Алексей1153 |
29.5.2013, 10:47
Сообщение
#5
|
фрилансер Группа: Участник Сообщений: 2939 Регистрация: 19.6.2010 Из: Обливион Пользователь №: 1822 Спасибо сказали: 215 раз(а) Репутация: 34 |
я бы при щелчке (двойном?) по строке открыл бы диалог редактирования записи. Юзер подправил, нажал, и, если что, ничего не сотрётся, просто предупреждение покажется, а диалог не закроется. И всегда можно отмену нажать. После подтверждения данные собираются и записываются
|
|
|
Steklova Olga |
29.5.2013, 11:16
Сообщение
#6
|
Участник Группа: Участник Сообщений: 198 Регистрация: 27.9.2011 Из: Санкт-Петербург Пользователь №: 2912 Спасибо сказали: 5 раз(а) Репутация: 4 |
открыл бы диалог редактирования записи В этом диалоге будут LineEdit, ComboBox, SpinBox... Модель у меня наследуется от QSqlRelationalTableModel. Вопрос: эти LineEdit, ComboBox, SpinBox можно (нужно) добавлять к мапперу QDataWidgetMapper? Как поместить данные из текущей записи в эти LineEdit, ComboBox, SpinBox? С помощью маппера? |
|
|
Алексей1153 |
29.5.2013, 11:19
Сообщение
#7
|
фрилансер Группа: Участник Сообщений: 2939 Регистрация: 19.6.2010 Из: Обливион Пользователь №: 1822 Спасибо сказали: 215 раз(а) Репутация: 34 |
да вручную поместить всё в конструкторе диалога ) В конструктор передать текущее содержимое строки. Откорректированное содержимое хранить в самом диалоге, а по итогу того, что вернётся из exec() - либо забыть всё, либо вытащить и записать в БД
|
|
|
Steklova Olga |
29.5.2013, 11:29
Сообщение
#8
|
Участник Группа: Участник Сообщений: 198 Регистрация: 27.9.2011 Из: Санкт-Петербург Пользователь №: 2912 Спасибо сказали: 5 раз(а) Репутация: 4 |
Алексей,
ComboBox'ы для связанных полей тоже вручную заполнять в конструкторе диалога? Или сделать это как-то с помощью маппера? А какой должен быть тип переменной - для передачи содержимого текущей записи в диалог? - для хранения в классе диалога откорректированного содержимого? |
|
|
Алексей1153 |
29.5.2013, 11:54
Сообщение
#9
|
фрилансер Группа: Участник Сообщений: 2939 Регистрация: 19.6.2010 Из: Обливион Пользователь №: 1822 Спасибо сказали: 215 раз(а) Репутация: 34 |
Steklova Olga, там для комбобокса, вроде, тоже модель можно установить. Но я никогда это не делал, обычно std::map в помощь (но у меня длинных списков не было)
тип - какой удобнее. Можно вообще создать экземпляр диалога, потом в его ui всё раскидать снаружи, после чего открыть. И так же после закрытия всё собрать. Диалог должен как можно меньше знать о том, что происходит снаружи него А про БД он вообще знать ничего не должен |
|
|
Steklova Olga |
29.5.2013, 12:24
Сообщение
#10
|
Участник Группа: Участник Сообщений: 198 Регистрация: 27.9.2011 Из: Санкт-Петербург Пользователь №: 2912 Спасибо сказали: 5 раз(а) Репутация: 4 |
|
|
|
Текстовая версия | Сейчас: 28.4.2024, 3:30 |