Консультация № 170108
02.07.2009, 21:09
0.00 руб.
07.11.2009, 14:35
0 15 2
Здравствуйте эксперты.
Как правильно реализовать следующую задачу.
Есть контрол ListVew c чекбоксами. Контрол заполнен всеми записями из таблицы Procs, содержащей поля ID и Proc_name. Есть ComboBox, в котором есть 3 вида ремонта. При выборе нужного ремонта -в ListVew отмечаются процессы(чекбоксы) соответствующие данному ремонту, согласно другой таблицы rem_proc, с полями rem(номер ремонта) и idproc(ID процесса из таблицы Procs).
Пользователь может сам определить входящие процессы в состав ремонта, устанавливая/снимая галки в чекбоксах. Для подтверждения данных изменений пользователь нажимает кнопку. так вот вопрос как правильно реализовать изменения в таблице rem_proc, данные(соответствие процесса ремонту) там могут и добавляться и удаляться.
варианты которые я предполагаю, например для ремонта 1.
1.Удаление всех записей из rem_proc с условием WHERE rem=1. Затем поэлементная проверка контрола ListVew и если элемент выбран добавление его в таблицу.
Мне не очень нравиться, что если вдруг сбой ПО или другие причины и данные были удалены, но не успели добавиться новые, может произойти потеря.
2. Цикл поэлементной проверки контрола ListVew и в зависимости от состояния элемента -добавление или удаление записи. Но тут возможно добавление повторных записей, поэтому наверное перед добавлением следует осуществлять поиск по таблице на присутствие существующих данных.
Второй вариант более безопасный, но обращений к таблице будет больше, может это не критично. Число записей в таблице 500-1000.
---
Может есть другой вариант? Например создание временной таблицы на основании данных чекбоксов и затем объединения временной таблицы и таблицы rem_proc. При котором нужные записи добавятся, а не нужные удаляться :-)
Вообщем что посоветоваете эксперты? Спасибо.

Обсуждение

Неизвестный
02.07.2009, 22:58
общий
это ответ
Здравствуйте, PsySex.

Можно завести два множества: добавляемые записи и удаляемые записи.
При установке чекбокса добавлять idproc в первое множество, при снятии - во второе.
Затем при коммите исключить их пересечение и поменять состояние базы данных (желательно в рамках одной транзакции, чтобы обеспечить атомарность).
5
Спасибо, за ответы! Это то, что мне нужно было :-)
Неизвестный
03.07.2009, 09:24
общий
это ответ
Здравствуйте, PsySex.
Честно говоря, так и не понял что у вас куда и откуда заносится, какая БД и какая среда разработки, но это не особо важно.
При количестве записей в 500 миллионов, ваш вопрос был бы актуален, а имея всего 500 записей, советую вам поступить по второму варианту + сделать проверку на наличие повторных записей в триггере вставки.
давно
Профессионал
848
1596
03.07.2009, 12:52
общий
Digitall:
я тоже думаю, что среда разработки не так важна, но если нужно -то разработка в VB6 доступ к MDB через ADO.
я привел свои примеры реализации. Но хотелось ответа профессионала, -и тут без разницы 500 или больше записей -нужен сам принцип -правльного обновления записей. Сегодня я делаю для 500, а завтра мож для 5 милионов буду ;-)
----
PS ответы оцениваю позже, когда все желающие отпишуться.
Неизвестный
03.07.2009, 14:12
общий
В вашем случае наверно лучше хранить некий флаг состояния каждой строки (выбрана из базы или новая, если из базы, то изменена или нет ) и по этому флагу проводить нужные действия (вставка в таблицу новой, или обновления существующей записи). Ну и само собой запоминать удаляемые строки.
Быстро, эффективно, и ничего в табличке не потеряется.
Кстати по поводу среды разработки: если бы использовали Oracle Forms, то подобный вопрос наверно даже и не возник.
Неизвестный
03.07.2009, 15:42
общий
PsySex:
Насколько я понял, вы пишете контрол, создающий ассоциации типа многие-ко-многим. Приведенная мной схема вполне рабочая и использовалась в одном фреймворке на ASP .NET.
Основная идея в том, чтобы запомнить состояние чекбоксов в начальный момент времени, а затем менять в базе только то что поменялось в списке.
Количество записей в таблице здесь не играет особой роли (вы ведь не собираетесь их выводить сразу все?)
давно
Профессионал
848
1596
03.07.2009, 21:50
общий
Digitall
лучше хранить некий флаг состояния каждой строки

Флаг где хранить в таблице или контроле? если в контроле(ListVew) или создать что-то наподобие массива -то не оч понимаю зачем в контроле видно состояние чекбоксом. Если в массиве(или в поле таблицы) -это значит, что если пользователь 10 раз снимет/поставит галку на элементе -я должен 10 раз обработать по сути безполезные операции- операции работы с флагом, -5 раз установил -5 раз сбросил -а конечный результат -ничего не изменилосьДумаю все операции должны производиться когда пользователь жмет на кнопку Применить.
Ross
запомнить состояние чекбоксов в начальный момент времени

По сути состояние запомнено по выборке SELECT * FROM rem_proc WHERE rem=1
Т.е. после выборки на основании отобранных ID процессов циклом я и расставляю чекбоксы.
Или вы предлагаете временную таблицу, скопировав туда данные по этой выборке, работать с ней, а потом добавить их в основную...Но опять же каждую снятую/утановленую галку я должен обрабатывать сразу...
====
Я вот сейчас подумал, может мне поступить так. Вообщем когда пользователь нажимает Применть -циклом прохожу по ListVew на основании чекбоксов создаю временную таблицу. Затем удаляю из основной записи касающиеся текущего ремонта и делаю INSERT в основную из созданной временой таблицы.
Мож ребят я зря заморачиваюсь -там собственно вся операция займет секунду, я тут задумыаюсь о потеряхПрога работает локально.
Неизвестный
03.07.2009, 23:11
общий
Нет, временных таблиц делать я не предлагал. Вот мои варианты решения:

1) Создать два объекта "множество" (std::set в STL С++, Set в Power Collections C#): before и after.
Запросить выборку idproc для rem=1. Расставить чекбоксы и занести все idproc в множество before.
После подтверждения изменения данных пройти по всем чекбоксам и занести отмеченные idproc в множество after. Убрать пересечение множеств before и after (то что не поменялось) из before и из after.
Получаем: в before - то что нужно удалить, в after - то что нужно добавить.

2) Создать два объекта "множество" toAdd и toDelete. В первое добавлять idproc если user ставит чекбокс, во второе - если снимает. Убрать пересечение множеств (то что было снято, а затем поставлено и наоборот).
И опять получаем, что нужно удалить, а что добавить.

Преимущество первого метода в том, что выполнение кода происходит только во время загрузки и коммита. Второй же менее требователен к ресурсам.
Неизвестный
03.07.2009, 23:21
общий
При желании можно обойтись и массивом, хранящим начальные значения чекбоксов.
После того как юзер нажмет на кнопку, пройти по чекбоксам и сравнить их значение с сохраненным.
давно
Профессионал
848
1596
03.07.2009, 23:50
общий
Ross:
я извиняюсь за свою назойливость
объясните пожалуста
Получаем: в before - то что нужно удалить, в after - то что нужно добавить

желательно в рамках одной транзакции, чтобы обеспечить атомарность

т.е. как удалить и добавить записи в один прием :-)
Неизвестный
04.07.2009, 00:22
общий
объясните пожалуста


чекбоксы
до (сохранено в массиве):
|1|0|0|0|0|1|0|0|0|0|

после:
|0|1|0|0|0|1|0|0|0|0|

значит нужно удалить procid, соотв. 1-му чекбоксу и добавить procid соотв. 2-му

как удалить и добавить записи в один прием


Для этого видимо нужно использовать методы объекта Connection:
BeginTrans(), CommitTrans(), RollbackTrans(). Вызываете BeginTrans, вставляете/удаляете записи, потом CommitTrans.
Если до вызова CommitTrans произойдет сбой, транзакция будет отменена. Кроме того можно ее отменить и самому: вызвать RollbackTrans (тоже только до Commit'a).
Точнее, к сожалению, объяснить не могу, т.к. не работал ни с ADO, ни с VB6.
давно
Профессионал
848
1596
04.07.2009, 08:00
общий
Ross:
Большое спасибо!!! Методы я нашел и успешно испробывал. спасибо за разъяснение как работает транзакция :-)
Неизвестный
12.07.2009, 17:46
общий
Здравствуйте PsySex.
возможно Вам это уже не интересно, но при использовании ListView значения before - after можно регистрировать без применения дополнительных массивов, используя Tag'и.
Евгений.
давно
Профессионал
848
1596
12.07.2009, 20:56
общий
Тесленко Евгений Алексеевич:
Спасибо Евгений Алексеевич.
Tag я правда использовал чуть в других целях ;-)
Неизвестный
13.07.2009, 16:51
общий
Здравствуйте PsySex.
думаю у Вас есть запас ведь Tag'и в ListView могут назначаться каждому элементу :
Код:
With ListView1.ListItems(1)
.Tag = "ItemTag"
.ListSubItems(1).Tag = "SubItemTag1"
.ListSubItems(2).Tag = "SubItemTag2"
'...
End With

Евгений.
давно
Профессионал
848
1596
13.07.2009, 20:26
общий
Тесленко Евгений Алексеевич:
Еще раз спасибо, этого не знал, в принципе в 1 раз пишу используя ListView, раньше пользовал MSFlexGrid.
Форма ответа