И снова конфликт совместного доступа | |
---|---|
Sandwich Автор Сообщений: 137 Дата регистрации: 08.02.2014 |
Здравствуйте
Собрался с силами и, прислушавшись к советам ssa и Igor Korolyov и других не менее уважаемых форумчан, решился навести порядок в работе с курсорадаптерами. А именно вынести все команды создания курсоров, добавления, изменения и удаления их строк в отдельные универсальные функции. Вроде получается, но дошел до tableupdate и теперь сижу и туплю: Создал функцию, производящую сохранение изменений в указанном курсоре:
в ней функция ShowError, которая все ошибки, кроме 1585 подробно выводит на экран:
Написал все это и сразу в голове много вопросов, на которые не могу найти ответов: 1. Если 1-й tableupdate (в строке 6) закончился неудачей, то по желанию пользователя либо перезапись либо отмена. Но 2-й tableupdate (в строке 9) тоже может успешно не завершиться по какой-то причине (да и tablerevert тоже). Их результаты тоже нужно проверять. Замкнутый круг? 2. Если мной изменялась 1 строка в курсоре, то вроде просто: если конфликт (строка изменилась другими) - перезаписать да/нет. А если я изменял много строк (пакетно) и конфликт может возникнуть в 5-й, 14-й, 123-й и т.д. строках. Для каждой переспрашивать? 3. Как быть если нужно не просто спрашивать "перезаписать да/нет?", а что-то типа: "поле Цена было 5, вы сохраняете 6, но кто-то уже поставил 4. перезаписать да/нет?" 4. Если п.2 "скрестить" с п.3, то вообще коллапс ... Кто-то может сказать, что я все слишком усложняю, но зато 1 раз написать функцию и на все ситуации. Буду благодарен советам. |
Re: И снова конфликт совместного доступа | |
---|---|
PaulWist Сообщений: 14601 Дата регистрации: 01.04.2004 |
1. TableUpdate необходимо обернуть в транзакцию, поскольку в "общем" случае сохранение происходит в больше чем одну таблицу.
2. Ошибки сохранения не обязательно связаны с конфликтом модификации юзера, поэтому сообщение 'Похоже другой пользователь изменил данные!' не совсем правильное. 3. Самое главное, существуют 3 стратегии сохранения данных а) первый сохранил, первый прав. б) последний сохранил, последний прав. с) последний решает сам. Опыт показывает, что если юзеру НУЖНО сохранить, то он ДОБЬЁТСЯ своего любыми способами, таким образом стратегия б) необходима в 99.99% случаев. ------------------ Есть многое на свете, друг Горацио... Что и не снилось нашим мудрецам. (В.Шекспир Гамлет) |
Re: И снова конфликт совместного доступа | |
---|---|
Sandwich Автор Сообщений: 137 Дата регистрации: 08.02.2014 |
Спасибо, по каждому из ваших пунктов: 1. Это функция апдейта одной таблицы и ЕЁ ВЫЗОВ планирую обернуть в транзакцию 2. 'Похоже другой пользователь изменил данные!' - только если ошибка 1585, по остальным алерт с кодами и описаниями этой ошибки 3. Согласен почти полностью. "Почти" потому что данные могут оказаться критическими (например деньги на счету и тд) Готов выслушать еще мнения |
Re: И снова конфликт совместного доступа | |
---|---|
AndyNigmatec Сообщений: 1551 Откуда: Волгоград Дата регистрации: 28.06.2015 |
Голосую: кто последний - тот и папа (с)
данные критические - но раз юзверь имеет права на их изменение - значит ему можно и нужно их менять, а ежели там логические условия (ну там остаток не менее нуля) - то можно же и триггер навесить к примеру Исправлено 1 раз(а). Последнее : AndyNigmatec, 28.08.18 10:32 |
Re: И снова конфликт совместного доступа | |
---|---|
Sandwich Автор Сообщений: 137 Дата регистрации: 08.02.2014 |
Если по такому принципу, то и вся функция не нужна, просто =TABLEUPDATE(1,.t.) и баста. Вопрос-то в том и стоит: как правильно (и красиво) сделать для тех 0.01% когда нужна экспертиза ДНК ))) |
Re: И снова конфликт совместного доступа | |
---|---|
AndyNigmatec Сообщений: 1551 Откуда: Волгоград Дата регистрации: 28.06.2015 |
ну и засунуть сию экспертизу в тригер, ежели отцовство установлено - то все ок, иначе - выбрасываем исключение ... как-то так вижу, но не настаиваю - условия то разные бывают
|
Re: И снова конфликт совместного доступа | |
---|---|
Sandwich Автор Сообщений: 137 Дата регистрации: 08.02.2014 |
Вопрос не где (в тригере, хп, просто функции), а как! |
Re: И снова конфликт совместного доступа | |
---|---|
AndyNigmatec Сообщений: 1551 Откуда: Волгоград Дата регистрации: 28.06.2015 |
Так на вопрос как - вы в самом первом посте и расписали )))
Как я понимаю возникли сомнения как обрабатывать возникающие ошибки/исключения - типа предлагать ли пользователю перезаписывать именно свои изменения и для каждой ли записи. Это не вопрос как - а вопрос идеологии, и на него PaulWist как раз и ответил. Доб. для каждой ли записи мучить пользователя сильно зависит от логики задачи - где-то может быть крайне назойливым 100500 вопросов пользователю при сохранении одного "документа" и логичнее ограничиться одним вопросом, а где-то может эта инфа об ошибках важна для каждой изменяемой записи. |
Re: И снова конфликт совместного доступа | |
---|---|
PaulWist Сообщений: 14601 Дата регистрации: 01.04.2004 |
Использовать: 1. Первичные ключи 2. Внешние ключи 3. Правила 4. Триггеры Ошибка, нарушение бизнес логики в этих сущностях БД автоматом сгенерит ошибку, которую поймает TableUpdate. ------------------ Есть многое на свете, друг Горацио... Что и не снилось нашим мудрецам. (В.Шекспир Гамлет) |
Re: И снова конфликт совместного доступа | |
---|---|
Igor Korolyov Сообщений: 34580 Дата регистрации: 28.05.2002 |
Сохранять "многозаписей" лучше по одной - в ручном цикле. При этом никаких messagebox "в процессе" сохранения, и тем более не стоит применять такую "вывернутую" схему как в приведенном коде (когда метод "извещения об ошибке" определяет "тип ошибки" для вызывающего кода).
Можно пробегаясь по изменениям (GetNextModified в помощь) и сохраняя их "по одному" набивать в какой-то буфер (от тупой строки до массива, или вспомогательного курсора) все произошедшие ошибки, НЕ применяя повторный force tableupdate и/или tablerevert. Потом уже, в конце, спросить за все ошибки и запускать повторный цикл по "непрошедшим" записям. Вообще подобным "скопом" сохраняют "несущественные" справочники (оставляя "непрошедшие" записи несохранёнными, а прошедшие фиксируя коммитом транзакции - не только фоксовой, но и ODBC-ной, что более важно). Либо табличные части документов - и при этом НЕ допускается никаких "частичных сохранений" - либо ВСЁ прошло, либо ничего. Но в этом случае вероятность получить конфликт совместного изменения весьма мала - т.к. для этого надо чтобы пользователи начали править один и тот же "документ" одновременно. Вариант с показом "что было, что мы ввели, что какой-то дядя ввёл пока мы думали" вполне возможен - рефреш записи после "неудачного" tableupdate и смотрим через OldVal() и CurVal() на "теневые" значения полей (соответственно "старое" и "то что сейчас на сервере" - "наше" значение напрямую как курсор.поле доступно, ну или через EVAL("курсор.поле") если опосредовано имена полей использовать). Я не уверен что эту схему имеет смысл применять для сохранения МНОГИХ записей за раз (это либо дичайшая форма где все подобные конфликты будут показаны, либо "по одному" придётся ходить и разрешать их - подтверждая перезапись, или отменяя свои изменения) - вот одной записи вполне логично и несложно будет. В FFC классы есть эту схему поддерживающие (но не для ODBC источников, насколько я помню, и совершенно точно не для CAD-ов) - код взять напрямую вряд ли получится, но идею подсмотреть вполне себе можно. И главное понять как именно получать всё что надо для рисования своего "разрешателя конфликтов".
------------------ WBR, Igor |
Re: И снова конфликт совместного доступа | |
---|---|
Sandwich Автор Сообщений: 137 Дата регистрации: 08.02.2014 |
Спасибо за совет, помогло. Но я уперся в одну проблему: GETNEXTMODIFIED возвращает номер строки, которая изменилась, не смотря на то что новое измененное значение не отличается от старого, т.е. было 5 поменяли на 5. Как это можно победить? Исправлено 1 раз(а). Последнее : Sandwich, 29.08.18 21:11 |
Re: И снова конфликт совместного доступа | |
---|---|
Sawradym Сообщений: 2244 Откуда: Винница Дата регистрации: 15.05.2007 |
Так не меняйте 5 на 5. Никто не мешает перед сохранением проверить не совпадают ли старое и новое значение и при совпадении просто пропускать сохранение. ------------------ |
Re: И снова конфликт совместного доступа | |
---|---|
Igor Korolyov Сообщений: 34580 Дата регистрации: 28.05.2002 |
Сам же говоришь - она ИЗМЕНИЛАСЬ Фокс не анализирует что на что меняется, он сам факт модификации фиксирует. Хочешь побыть умнее разработчиков, просто в том же цикле проверяй значения в "помеченных как изменённые" полях (GETFLDSTATE(-1) покажет какие поля фокс считает изменёнными, и потом сравнивай OLDVAL(имя_поля) и EVAL(имя_поля)). Можно через TableRevert() "отменить" эти фиктивные правки.
Хотя в общем случае даже изменение "само на себя" МОЖЕТ иметь прикладной смысл. Например триггер может пересчитать какие-нить поля, ту же "дату последнего изменения" или "автор последнего изменения". А если там есть какая мега-бизнес-логика, то это (менять поле "само на себя") можно применять как запускалку соответствующей логики. Опять же, в конкурентной/многопользовательской среде попытка поменять "Вася" на "Вася" НЕ является бессмысленной - может быть в середине процесса редактирования пользователем инфы кто-то прописал туда вместо "Васи" "Колю", и это уже не будет изменение "самого себя на само себя" - хотя клиент до начала сохранения и не видел что там были конкурентные модификации (увидит при попытке такого вот фиктивного сохранения - тот самый Update Conflict). P.S. "пропускать" сохранение в общем случае нельзя - для тех же операций перезапроса/CursorRefresh курсор должен быть "чистым" - незафиксированные изменения (даже "фиктивные") не дадут обновить курсор. Так что если уж и надо "игнорировать изменение 5 на 5", то надо для этой записи TableRevert сделать. ------------------ WBR, Igor Исправлено 1 раз(а). Последнее : Igor Korolyov, 29.08.18 22:37 |
Re: И снова конфликт совместного доступа | |
---|---|
Sandwich Автор Сообщений: 137 Дата регистрации: 08.02.2014 |
Эх! Надеялся что чего-то "секретного" не знаю и хотел обойтись без этого. |
Re: И снова конфликт совместного доступа | |
---|---|
Igor Korolyov Сообщений: 34580 Дата регистрации: 28.05.2002 |
Нет ничего "секретного" - просто такие изменения сохраняют и всё Ну а кому надо геморроя - извращаются отделяя их от "настоящих изменений"
------------------ WBR, Igor |
Re: И снова конфликт совместного доступа | |
---|---|
Sandwich Автор Сообщений: 137 Дата регистрации: 08.02.2014 |
да я и сохраняю, только tableupdate на такой записи возвращает .f. и приходится его игнорировать |
Re: И снова конфликт совместного доступа | |
---|---|
Igor Korolyov Сообщений: 34580 Дата регистрации: 28.05.2002 |
Если возвращает .F. то надо смотреть AERROR(), возможно команды генерируемые для сервера, или просто лог на сервере и устранять причины ошибки - не должен он так работать... ------------------ WBR, Igor |
Re: И снова конфликт совместного доступа | |
---|---|
Sandwich Автор Сообщений: 137 Дата регистрации: 08.02.2014 |
Всем снова здравствуйте
Решил не париться и многозаписи сохранять TABLEUPDATE(1,.t.,lcCursor1). Один раз апдейт завершился ошибкой о том, что пытаюсь записать не уникальную запись по уникальному ключу. Вопрос: записи, которые апдейтились до этой ошибки сохранились в БД или "откатились вместе с ошибкой"? |
Re: И снова конфликт совместного доступа | |
---|---|
Igor Korolyov Сообщений: 34580 Дата регистрации: 28.05.2002 |
Если сохранение не обёрнуто в транзакцию (локальную для dbf, серверную для ODBC) то будут сохранены.
------------------ WBR, Igor |
Re: И снова конфликт совместного доступа | |
---|---|
Sandwich Автор Сообщений: 137 Дата регистрации: 08.02.2014 |
Не успел написать: сам проверил - сохранилось. А причина оказалась в следующем: При операциях (вставка/изменения) сначала проверял на уникальность с помощью LOCATE - все было нормально (дубликаты исключались). Но сегодня провел тест на быстродействие, сравнивая скорость LOCATE и SELECT. SELECT "выиграл" со счетом 9 сек (10 000 запросов) против 17 сек (10 000 LOCATE-ов). Я обрадовался и везде поменял локейты на селекты. Скорость возросла. Однако это привело к такому аварийному завершению TABLEUPDATE: оказывается SELECT "не видит" вставленные через INSERT значения в буфферизированный курсор. А LOCATE прерасно "видит". Можно как-то "протереть глаза" селекту? Вопрос снят - хэлп рулит. Исправлено 1 раз(а). Последнее : Sandwich, 15.09.18 20:49 |
© 2000-2024 Fox Club  |