|
|
|
Удаление (корректировка) группы записей при буферизации
|
|||
|---|---|---|---|
|
#18+
ВОПРОС 1. Возникнут ли у меня ошибки при работе в сети, если я с двумя FREE TABLES провожу подобную операцию удаления? * ВОПРОС 2: нужна ли след. строка для конкретно для этой задачи? Set Exclusive Off Set Multilocks On Use teams In 0 Shared Use players In 0 Shared CursorSetProp("Buffering",5,'teams') CursorSetProp("Buffering",5,'players') ... Locate For teams.Name='Алания' ... If 6=Messagebox('Удалить?',4+32+256) Delete All For players.idTeam=teams.idTeam In players * ВОПРОС 3. Стоит ли заменить предыдущую строку нижеследующей? * DELETE FROM players WHERE players.idTeam=teams.idTeam IF Tableupdate(.T.,.T.,'players') * успешно удалены игроки ENDIF Delete In teams IF Tableupdate(.F.,.T.,'teams') * успешно удалена команда ENDIF Endif Собственно, ЗАГОГУЛИНА :) в том, что подходящий примерчик из книги с TRANSACTION тут не применить, т.к. это - не БД. А операция массового удаления в players не проверяет успешность удаления каждой конкретной записи. Может, цикл писать на проверку TableUpdate()=.T. ? Или TableUpdate(.T.,.T.) все нипочем, лишь бы сервер не отрубился? А вариант DELETE-SQL вроде сам должен разобраться с блокировками и удалениями... ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.11.2005, 06:19 |
|
||
|
Удаление (корректировка) группы записей при буферизации
|
|||
|---|---|---|---|
|
#18+
1. Без транзакции - обязательно. В версии VFP9 есть возможность наложить транзакцию на свободные таблицы 2. Да. Поскольку в таком контексте, команда DELETE будет сравнивать каждую запись таблицы Players с одной единственной (текущей) записью из таблицы Teams. Поэтому предварительная установка указателя на нужную запись просто необходима. 3. Без разницы. Удаление ведь будет происходить не в исходной таблице, а в буфере таблицы. Причем еще не факт, что команда Delete-SQL сможет найти все нужные записи. Она ведь может проверять условие WHERE не в буфере, а в исходной таблице. Со свободными таблицами у тебя только один вариант действия: перед сбросом буфера попытаться вручную заблокировать нужную таблицу. Примерно так: Код: plaintext 1. 2. 3. 4. 5. В противном случае нет никакой гарантии в том, что будут удалены ВСЕ записи. Т.е. может оказаться так, что будет сброшен буфер только для некоторых записей, а остальные так и остануться не удаленными. Впрочем, если для твоей задачи это не имеет значения, то можешь и не блокировать таблицы. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.11.2005, 14:21 |
|
||
|
Удаление (корректировка) группы записей при буферизации
|
|||
|---|---|---|---|
|
#18+
ВОПРОС 1. У меня 8-й VFP. Стало быть, транзакции free tables не для меня ? ВОПРОС 2. Ошибочка вышла, следует читать так: * ВОПРОС: нужна ли следующая строка конкретно для этой задачи? Set Multilocks On ….. Кстати, после вашего ответа, появился новый ВОПРОС 2а А если в тот момент, когда идет удаление в дочернем файле, в родительском "доброжелатели грохнут" запись для сравнения? С чем тогда сравнивать? Или эталон в любом случае остается в моем буфере, пока я его сам не "замочу"? ВОПРОС 3. Почему команда Delete-SQL не сможет найти все нужные записи? Если она будет проверять условие WHERE не в буфере, а в исходной таблице, то это ж еще лучше. Там-то все реальные записи и живут. Или она непредсказуемо выбирает место своей деятельности: буфер или таблицу? "…если для твоей задачи это не имеет значения, то можешь и не блокировать таблицы." Это как надо понимать ? То, что я поиграл с буфером, а в таблицу реально ничего не сбрасываю? Или то, что у меня незагруженная сеть и столь редки конфликтные ситуации, что особенно и беспокоиться не о чем? ******************************** За основу сброса изменений взял ваш, Владимир М., примерный код кнопки "Сохранить" в режиме оптимистической табличной буферизации (5) Правда, у меня не БД, а отдельные таблицы. Поэтому пришлось закомментировать следующие три строки: BEGIN TRANSACTION END TRANSACTION ROLLBACK Но при следующей последовательности событий выплыл эффект реанимации: 1. Первый user открывает запись на корректировку. 2. Второй тем временем удаляет эту запись 3. Пытается сбросить изменения с Tableupdate(.F., .F.) 4. Естественно появляется предложение записать поверх. 5. Ответ "ДА". 6. Tableupdate(.F., .T.) И тут чудо: удаленная запись восстанавливается со значениями первого user. По логике, думаю, так и должно быть. Все бы ничего, но могли быть удалены связанные записи в дочерних free tables. Поэтому у меня ВОПРОС 4. Вы даете примерный код, не утруждаясь на доп. разбор такой мелочи? И в код программы нужно внести доп. обработку записи? Типа: IF Curval("Deleted()") =MessageBox('А записи-то уже нет, дружок!', 0) ENDIF ВОПРОС 5. Если я сам собираюсь изменить/удалить связанную с нею группу дочерних, то могу я так поступить? SELECT players DELETE ALL FOR players.idTeam=teams.idTeam IN players IF FLOCK() = .T. =TABLEUPDATE(.T.,.T.) UNLOCK ENDIF Или вторую и третью строки программы стоит поменять местами? Кстати, непонятно, в чем преимущество DELETE-SQL перед DELETE, если особого тока от ее блокировок нет? Да еще и может уменьшить производительность. Или оно только в БД проявляется? ВОПРОС 6. Собственно у меня нет полной ясности с Tableupdated( lAllRows) , когда lAllRows =.T. Скорость работы при оптимистической буферизации сильно зависит от того, 3-я это или 5-я? Или 5-я буферизация была введена, по большей части, для подобных однострочных, но "оптовых" операций с записями, а не для ускорения скорости путем "накопительства"? Не лучше ли, не отходя от кассы, сразу обрабатывать текущие изменения, не накапливая "на потом"? Но для этого, вроде есть "3-й вид оптимизма". 7. Кстати, а есть возможность сбрасывать, например в WORD, блоки русскоязычного текста в толковой кодировке? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.11.2005, 18:06 |
|
||
|
Удаление (корректировка) группы записей при буферизации
|
|||
|---|---|---|---|
|
#18+
ВОПРОС 1, 2, 2а А самому попробовать? 5 минут экспериментов и все ясно. Не надо ждать пока тебе кто-то ответит. ВОПРОС 3 Ты изменил в буфере значение поля players.idTeam на то значение, которое впоследствии служит признаком отбора записей на удаление. Надо ли удалить и эту запись тоже? ВОПРОС 4 Насколько вероятна такая ситуация? Кто в этом случае прав? Тот кто удалил или тот кто восстановил? Откуда я знаю? Это как раз те "мелочи", которые каждый решает в зависимости от постановки задачи. Тем более, Вы отказались от контейнера базы данных и теперь пытаетесь реализовать сильно навороченным программированием то, что элементарно решается через Referenty Integrities в контейнере базы данных. И это далеко не единственная проблема с которой Вы столкнетесь из-за работы с Free Tables. ВОПРОС 5 Команда DELETE модифицирует буфер. Поэтому другие пользователи о ней просто ничего не знают. Хотя с точки зрения возможного отката изменений, более корректно сделать попытку блокировки ДО команды DELETE. ВОПРОС 6 Тип буферизации не имеет никакого отношения к скорости. Это разный способ контроля буфера таблиц. Строковый - это полуавтоматический. При определенных условиях буфер сбрасывается автоматически (по крайней мере пытается, со всеми последствиями в виде сообщений об ошибках). Без контроля со стороны пользователя или программста. Табличный - это полный контроль со стороны программиста. Никаких автоматических попыток сброса буфера. Исключительно по команде TableUpdate(). ВОПРОС 7 Конечно. А какие проблемы? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.11.2005, 18:56 |
|
||
|
Удаление (корректировка) группы записей при буферизации
|
|||
|---|---|---|---|
|
#18+
Конечно, скучно помогать упрямцу следующему порочным маршрутом. :) Владимир М., я согласен с вами, БД была бы правильнее F/Tables. Но проблема в том, что у меня не получается классическое, как в книжных примерах, построение. Глядя на то, как она организуется, я не пойму, как этот "уродец" будет жить? Моя задача гораздо сложнее, но суть проблемы проще представить таким образом: должны быть 1. справочник по агентам: agent - idAGENT (AutoInc, код агента), - nOPERATOR (оператор, последним работавший со справочной информацией по этому агенту), - прочая справочная информация об агенте. 2. справочник по операторам: operator - idOPERATOR (AutoInc код оператора), - прочая справочная информация по оператору. 3. справочник по городам town - idTOWN (AutoInc, код города), - прочая справочная информация по городу. 4. собственно рабочий файл zakaz - nAGENT агент - nTOWN_FROM (откуда товар взял) - nTOWN_TO (куда перевез) - nOPERATOR (оператор, оформивший заказ) - прочая информация Как видно, справочник по операторам должен быть прицеплен сразу к agent и zakaz, а справочник town к двум полям в zakaz. Если все эти 4 файла сцепить нитками связей в Database–дизайнере, то мне кажется, что ничего не будет работать, т.к. этот квартет будут раздирать внутренние противоречия. В файлах zakaz и operator VFP может потребоваться одновременно сделать активными по 2 записи. А открывать дополнительные курсоры Designer не позволяет, хотя и не возражает против столь дикой, IMHO, реляции файлов в БД. 5-мин. экспериментом тут не отделаешься, тем более, что одних только справочников у меня далеко не 3. Поэтому я и направился по пути free tables. Мне казалось, что так проще надежнее… Может, я зря в панику ударяюсь? И VFP прекрасно "разрулит" все дела в этой БД? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 22.11.2005, 05:00 |
|
||
|
Удаление (корректировка) группы записей при буферизации
|
|||
|---|---|---|---|
|
#18+
Вы перепутали понятия. Связи в контейнере базы данных - это вовсе не обязательная вещь. Это всего-лишь инстурмент для автоматической генерации некоторых триггеров. В FoxPro недопустимо делать дублирующие связи. Т.е. настраивать между двумя таблицами две разные связи. В данном случе не пройдет связка между таблицей городов (town) и рабочей таблицей (zakaz), поскольку здесь требуется установить 2 паралельные связи. Но, не пройдет только автоматическая связь. Можно ведь настроить это все вручную. Т.е. взяв за образец те триггера, которые генерит Referential Integrity, создать свой собственный триггер. Просто, если делать базу данных на свободных таблицах, то сам процесс написания того, что делает триггер чрезвычайно усложняется. Не говоря уже про отсутствие транзакций. Собственно, почитайте по триггерам статью Триггер Ну, и для большей ясности о связях Связи и отношения между таблицами Тут важно понять простую вещь. Все то, что делается в FoxPro через дизайнеры, во-первых, всегда "ущербно". Не в смысле "не правильно", а в смысле "ограничено". Поскольку далеко не все возможные ситуации можно автоматизировать. А, во-вторых, все то, что делает дизайнер ВСЕГДА можно повторить программно БЕЗ дизайнера. Ну, а раз дизайнером не пользуемся, то получаем значительно больше возможностей. Устраняются ограничения, накладываемые собственно дизайнером. Т.е. зря в панику ударились. ВСЕ контейнер базы данных не разрулит. Но он позволит существенно облегчить процесс написания приложения. Автоматические триггера снимут хотя бы часть проблем, что само по себе ценно. Все остальное - уже придется писать вручную. Но написать код триггера задача существенно более простая, чем писать технологию обеспечения ссылочной целостности на свободных таблицах. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 23.11.2005, 00:01 |
|
||
|
Удаление (корректировка) группы записей при буферизации
|
|||
|---|---|---|---|
|
#18+
Hi men dea! > Как видно, справочник по операторам должен быть прицеплен сразу к agent и > zakaz, а справочник town к двум полям в zakaz. Это нормальная ситуация для БД. > Если все эти 4 файла сцепить нитками связей в Database-дизайнере, то мне > кажется, что ничего не будет работать, т.к. этот квартет будут раздирать > внутренние противоречия. В некоторых версиях фокса, при генерации тел триггеров ссылочной целостности есть ошибка, которая проявляется как раз в ситуации когда из одной таблицы имеется более одной связи к другой таблице (как у тебя в случае со связкой заказ-город). Но эта ошибка довольно легко исправляется, после чего никаких проблем не возникает. И никакие "противоречия" никого "раздирать" не будут. Тем более что ты строишь свою схему на основании AUTOINC полей, и тем самым сразу отвергаешь любые нездоровые попытки модификации поля первичного ключа (и если собственно AUTOINC я лично недолюбливаю, то подобное ограничение на правку PK - могу лишь приветствовать). Сделать тест для твоей базы - это если не 5, то 10 минут - в т.ч. сгенерировать все триггера, и посмотреть как они себя поведут в случае попыток нарушения ссылочной целостности. Как совет - не покупайся на cascade, хотя это и звучит круто - это весьма своеобразное правило, и применяется оно не так часто как Restrict - т.е. простое поддержание целостности путём запрета операций эту самую целостность нарушающих. Если действтельно интересно - посмотри как "внутри" работают тригера созданные построителем - увидишь, что никакого конфликта там не будет - для своих целей триггера повторно открывают (а потом конечно закрывают) нужные таблицы. Posted via ActualForum NNTP Server 1.3 ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 23.11.2005, 00:38 |
|
||
|
Удаление (корректировка) группы записей при буферизации
|
|||
|---|---|---|---|
|
#18+
Hi Владимир! > В FoxPro недопустимо делать дублирующие связи Они не дублирующие, они разные - от поле1 к Справочник_PK и от поля2 к Справочник_PK (т.е. 2 внешних ключа, ссылающихся на одну таблицу) - это вполне допустимо для фоксового контейнера БД. Другой вопрос, что есть небольшая помарочка в RI триггерах - я помнится описывал где и что надо "подкрутить" чтобы и для таких связей корректно работал RI. Posted via ActualForum NNTP Server 1.3 ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 24.11.2005, 02:51 |
|
||
|
Удаление (корректировка) группы записей при буферизации
|
|||
|---|---|---|---|
|
#18+
"Вы перепутали понятия" Понял, что означает эта фраза, только после того, как экспериментальный вариант БД заработал. :) Вы правы. Подобные "нитки" (2 к 1 и 1 к 2) прокатывают. Что не понравилось: 1. Надоело везде выставлять RESTRICT после каждого изменения. Чуть поменял что-то в структуре файла или чихнул, – тут же исправляй REFERENTIAL INTEGRITY. Они по умолчанию упрямо превращаются в IGNORE. Есть способ, чтобы сразу все состояния перегонять в RESTRICT? 2. Когда ввожу новую запись, (например, в zakaz), хотелось все пункты формы-бланка содержали белые (пустые) поля. Видно, где уже данные ввел, а где нет. В реальной задаче миллион справочников, и не все поля вводится по порядку. Бланк будет содержать многостраничный PageFrame и от значений будет в глазах рябить. .NULL. не во всех случаях допустимо, а непустой default может оказаться не таким, что нужно по логике задачи. Смотришь, вроде все заполнено, а что-то забыл переставить в нужное состояние, и "пошла" гулять ошибка оператора, хотя INTEGRITY is OK. APPEND BLANK с готовыми пустыми значениями вызывает ошибку триггера, а присваивать default "абы что-нибудь" не хочется… Как и вводить в справочники нулевые значения. Пришлось навесить на кнопку НОВАЯ ЗАПИСЬ дополнительно APPEND BLANK (со значениями default) SCATTER memvar BLANK EXCEPT поля AutoInc GATHER memvar чтобы переписать значения "удобной пустотой". Ведь до тех пор, пока не сделана TABLEUPDATE ошибки не будет… Что обычно делают в этих случаях? 3. Когда при вводе происходит ошибка, то непонятно, в каком из полей произошло нарушение целостности. Приходится пробежаться по всем, проверить самому. В Free Tables так и делал, чтобы ошибки не было. Вешал на кнопку СОХРАНИТЬ что-то вроде: Do Case Case Empty(mycursor.MYFIELD) && или иная проверка Thisform.Pageframe1.ActivePage=1 Thisform.Pageframe1.Page1.tMYFIELD.SetFocus() ….. Endcase Может, где-то имеется готовая ссылка на поле – причину беспокойства триггера? Aerror() не возвращает, вроде… ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 25.11.2005, 21:10 |
|
||
|
Удаление (корректировка) группы записей при буферизации
|
|||
|---|---|---|---|
|
#18+
Hi men dea! 1) У меня ничего не "слетает" конечно если не разрушать и не пересоздавать сами связи. 2) Установить их можно програмно - открыв dbc как dbf (USE MyDB.dbc IN 0 AGAIN ) и там заменив 3 символа в поле RIInfo для записей с Objecttype="Relation" - эти 3 символа - типы ограничений. т.е. RRR - это restrict по всем 3-м операциям. Конечно от необходимости запускать RI построитель и перегенерировать код это не избавляет - ЕСЛИ конечно появились новые связи или существенно изменились связанные таблицы (в плане полей связи конечно). Иначе ничего делать не надо - рабортоспособность уже созданного триггера не завивит от наличия связи в БД (именно для триггеров создаваемых штатным построителем RI!!! Для других триггеров это может оказаться более критично). 3) Разберись с буферизацией. Если включена буферизация, то можно добавлять пустую запись - триггера будут работать ТОЛЬКО при попытке её сохранения. А вообще часть довольно удобно держать в справочниках служебные записи - например с кодом 0 и надписью типа "не заполнено" - т.е. можно тогда даже сохранять "неполные" записи - а уже отдельными режимами искать всех подобных "недозаполненных" и решать что с ними делать. Представь что пользователю по зарез надо ввести скажем клиента, а из какого он города, или на какой улице его офис - он не знает. Не стоит запрещать ему ввод значения типа "не знаю" :) 4) NULL в качестве внешнего ключа мне не нравтся, а вот для полей не связанных ни с чем - он вполне уместен - через SET NULLDISPLAY можно его "красиво" отображать. 5) Если ты имел в виде ошибку триггера - то надо смотреть глобальный массив gaErrors - его создаёт и заполняет любой триггер в случае ошибки (конечно опять таки это особенность триггера созданного RI построителем. Твой триггер может возвращать такую информацию иными средствами). AERROR() конечно будет просто сообщать что Trigger Failed... Posted via ActualForum NNTP Server 1.3 ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 26.11.2005, 02:18 |
|
||
|
|

start [/forum/topic.php?fid=41&msg=33393620&tid=1592933]: |
0ms |
get settings: |
6ms |
get forum list: |
19ms |
check forum access: |
3ms |
check topic access: |
3ms |
track hit: |
183ms |
get topic data: |
13ms |
get forum data: |
3ms |
get page messages: |
70ms |
get tp. blocked users: |
2ms |
| others: | 198ms |
| total: | 500ms |

| 0 / 0 |
