Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Базы";
Текущий архив: 2002.04.11;
Скачать: [xml.tar.bz2];

Вниз

Cached Updates update failed?   Найти похожие ветки 

 
kaif   (2002-03-21 10:59) [0]

Допустим, у меня имеется 3 записи в таблице:
ID N
1 2
1 3
1 4
Поля ID,N составляют первичный ключ.

Беру IBQuery + IBUpdateSQL.
CachedUpdates = True.

Вписываю все, как надо:

UPDATE ...
SET N=:N
WHERE ID=:OLD_ID AND N=:OLD_N

Потом в цикле меняю:
with MyQuery do
begin
i := 0;
First;
while not Eof do
begin
inc(i);
FieldByName("N").AsInteger := i;
Next;
end;
ApplyUpdates;
end;

ApplyUpdates проваливается на первой же строке! (update failed).
Как такое может быть? Ведь для первой записи нарушения первичного ключа никак не предвидится...

Хочется после удаления строки из документа перенумеровать его строки. И чтобы без гимора. Но, как я чувствую - ничего не получается и придется использовать суррогатную нумерацию (с дырками) для N...
Или я не прав?


 
Turalyon   (2002-03-21 11:11) [1]

У тебя какой вид имеет MyQuery.SQL???

А вообще у тебя база не в режиме редактирования, а ты что то присваиваешь полям...

with MyQuery do
begin
i := 0;
First;
while not Eof do
begin
Edit;
inc(i);
FieldByName("N").AsInteger := i;
Post;
Next;
end;
ApplyUpdates;
end


 
kaif   (2002-03-21 11:49) [2]

Извиняюсь, просто я не написал здесь в вопросе Edit. Но у меня это написано в программе. Post не нужен, так как Next делает Post, хотя и не помешает. Нет, проблема в чем-то другом. Везде, где я использую CachedUpdates я сталкиваюсь с этой проблемой.
Если удалил строку из набора, в котором второе ключевое поле имело сквозную нумерацию в таблице, то потом либо надо мириться с "дыркой", либо не использовать CashedUpdates.
Запрос у меня нормальный, просто все приводить -слишком длинно.


 
Alexandr   (2002-03-21 11:52) [3]

Update Failed означает, что у тебя при выполнении запроса при вносе изменений в одной записи таблицы обновилось в базе <>1 записей


 
kaif   (2002-03-21 12:08) [4]

Спасибо, Alexandr, это интересная информация. Попробую это использовать. Я обязательно хочу разобраться, что тут происходит. CachedUpdates слишком приятная вещь, чтобы от нее отказываться, не выяснив, в чем тут дело.
Просто нонсенс какой-то
UPDATE ...
SET N=:N
WHERE ID=:OLD_ID AND N=:OLD_N
А втаблице PRIMARY KEY(ID,N)
Но двух записей с одинаковыми значениями ключа в принципе быть не может...


 
Alexandr   (2002-03-21 12:13) [5]

значит может быть 0 записей.


 
kaif   (2002-03-21 12:28) [6]

А... Интересно, может, действительно 0 записей? А что, API клиента IB поставляет информацию о количестве измененных строк? Или update failed - это ошибка, которую сервер присылает?
Как вообще компонент узнает, что обновилось <>1 записей?


 
Alexandr   (2002-03-21 12:36) [7]

апи такую информацию предоставляет.
И используется она и в BDE и в IBX


 
kaif   (2002-03-21 12:37) [8]

Я вставил в цикл:
Post;
if i = 2 then
break;

Next;
Ошибка опять есть.
Тогда я вставил
Post;
if i = 1 then
break;

Next;
Ошибка исчезла.
Если это все же нарушение PRIMARY KEY, например, предположим, что компонент обходит набор задом наперед, тогда такое может быть, то почему сообщение не о нарушении PRIMARY KEY, а об Update Failed?
Дурдом какой-то. Сейчас полезу в API искать, может, все CachedUpdates как-то одним махом на сервер посылаются?... Хотя мне казалось, что это не так.


 
Turalyon   (2002-03-21 12:48) [9]

Попробуй не делать сразу ApplyUpdates а в этом месте посмотреть что у тебя происходит с НД.


 
kaif   (2002-03-21 12:54) [10]

Я посмотрел в IBSQLMonitor:

[Application: Allegro]
: [Prepare] update GAAP_POS
set
N = :N,
IS_CREDIT = :IS_CREDIT,
ACC = :ACC,
OBJ = :OBJ,
AMOUNT = :AMOUNT,
LAYER = :LAYER,
QUANTITY = :QUANTITY,
UNIT = :UNIT
where
ID = :OLD_ID and
N = :OLD_N


Plan: PLAN (GAAP_POS INDEX (RDB$PRIMARY32))
[Application: Allegro]
: [Execute] update GAAP_POS
set
N = :N,
IS_CREDIT = :IS_CREDIT,
ACC = :ACC,
OBJ = :OBJ,
AMOUNT = :AMOUNT,
LAYER = :LAYER,
QUANTITY = :QUANTITY,
UNIT = :UNIT
where
ID = :OLD_ID and
N = :OLD_N


N = 1
IS_CREDIT = 0
ACC = 5
OBJ = 0
AMOUNT = 1000
LAYER = 1
QUANTITY = 0
UNIT = 0
OLD_ID = 100000
OLD_N = 1
Далее уже пошла Update Failed.
======================
Самое странное здесь то, что N=1 для OLD_N=1, хотя по логике у меня ведь OLD_N как раз равно 2 ("дырка" в начале набора). Это, видимо и вызывает update 0 записей, так как в таблице нет записи с N = 1!
Это что, ошибка в IBX?


 
Alexandr   (2002-03-21 12:55) [11]

отсылаются по одному и после каждого проверяется, чтобы обновилать только одна запись


 
kaif   (2002-03-21 13:32) [12]

У меня такое ощущение, что OLD_N существует только в контексте апдейта одной строки, а не всего набора. Но как тогда это все вообще работает? Где запоминаются все эти OldValue? Может, для ключевых полей это IBQuery делает как-то иначе, чем для остальных полей, считая, что ключевые поля не должны изменяться и просто полагает, что раз поле ключевое (WHERE ID=:OLD_ID AND N = :OLD_N), то нужно просто считать N тождественным OLD_N ?


 
Turalyon   (2002-03-21 13:37) [13]

Это конечно не очень хорошо, но пробовал ли ты внести ApplyUpdates в цикл? И применять изменения после каждого прохода.


 
Johnmen   (2002-03-21 13:47) [14]

>Turalyon © : Тогда уж проще отключить кэширование...


 
kaif   (2002-03-21 13:56) [15]

согласен с Johnmen, что это тождественно отключению CachedUpdates. Вообще, я понимаю, что программирование - наука эмпирическая, но не до такой же степени! Какое-то объяснение должно быть! Если бы я лично для себя волновался, то просто сделал бы CachedUpdates без всяких Apply, а по кнопке "Сохранить" вызывал бы в отдельном запросе
DELETE FROM GGAP_POS WHERE ID=:ID
одним махом, а потом просто обходил бы IBQuery и просто для всех строк заново инсертил еще одним запросом... Иногда я такой подход применяю. Но в данном случае я должен дать технологию в руки конфигурирующему (я пишу гибкую программу на основе DreamControls) и для редактирования detail-таблиц документов хотел предложить что-то изящное. Поэтому мне нужно разобраться. Если надо, я изменю исходный текст IBQuery, только, чтобы это все работало.


 
kaif   (2002-03-21 13:59) [16]

Вообще, помнится мне, что тут на форуме не раз спрашивали про CachedUpdates и Update Failed, но я не могу никак найти эти ветки через "Поиск"...


 
Alexandr   (2002-03-21 14:02) [17]

дык у тебя же есть исходники IBX проследи, чего там делается и откуда ошибка вылазит.
Делов-то...


 
Turalyon   (2002-03-21 14:08) [18]

>kaif © & Johnmen ©
Дык я понимаю что это плохо, я предложил попробовать...


 
kaif   (2002-03-21 14:35) [19]

Я пошагово смотрю, что делается в TIBUpdateSQL.SetParams:

for I := 0 to Params.Count - 1 do
begin
Param := Params[I];
PName := Param.Name;
Old := CompareText(Copy(PName, 1, 4), "OLD_") = 0;
if Old then
System.Delete(PName, 1, 4);
Field := FDataSet.FindField(PName);
if not Assigned(Field) then
Continue;
if Old then
Param.AssignFieldValue(Field, Field.OldValue) else
begin
Value := Field.NewValue;
if VarIsEmpty(Value) then
Value := Field.OldValue;
Param.AssignFieldValue(Field, Value);
end;
end;
=============
Так вот, флаг Old выставляется правильно, но почему-то Field.OldValue здесь уже 1, хотя должно быть 2... Как я и предполагал, он присваивает где-то раньше Field.OldValue новое значение...
Любопытно, что если я модифицирую только 1 запись (выскакиваю из цикла по i=1), то Field.OldValue = 2, как и должно быть!


 
Johnmen   (2002-03-21 15:42) [20]

А м.б. использовать IBDataSet с прописанными InsertSQL и т.д.


 
kaif   (2002-03-21 15:49) [21]

Довольно трудно распутать этот клубок с CachedUpdates, но там точно ошибка, причем у меня версия IBX6.2 (не сказать, чтобы совсем старая...). Оказывается, Field.OldValue переводит DataSet (!!!) в состояние dsOldValue, а потом просто возвращает AsVariant поля. Само AsVariant уже вызывает метод потомка (в данном случае TIntegerField), который тоже ничего особенно интересного не делает, пока дело не доходит до:

function TIBCustomDataSet.GetActiveBuf: PChar;
begin
case State of
dsBrowse:
if IsEmpty then
result := nil
else
result := ActiveBuffer;
dsEdit, dsInsert:
result := ActiveBuffer;
dsCalcFields:
result := CalcBuffer;
dsFilter:
result := FFilterBuffer;
dsNewValue:
result := ActiveBuffer;
dsOldValue:
if (PRecordData(ActiveBuffer)^.rdRecordNumber =
PRecordData(FOldBuffer)^.rdRecordNumber)
then
result := FOldBuffer
else
result := ActiveBuffer;
else if not FOpen then
result := nil
else
result := ActiveBuffer;
end;
end;
=========================
Так вот тут это странное условие
PRecordData(ActiveBuffer)^.rdRecordNumber =
PRecordData(FOldBuffer)^.rdRecordNumber

оказывается неистинным. Что оно означает, я в толк не возьму?...
======
Я попробовал CancelUpdates, предположив, что FOldBuffer просто куда-то теряется, но CancelUpdates великолепно работает, восстанавливая старые значения любых ячеек, в том числе и ключевых (N). Таким образом, получается, что задумано верно и как-то это все должно было работать, так как все OldValue для всего набора где-то хранятся.
Но там указатель на указателе сидят и сдвиги по буферам опираются на RecordNumber - разобраться не так легко...


 
kaif   (2002-03-21 15:52) [22]

Попробую IBDataSet. Может, там эта ошибка не проявится? Если нет IBUpdateSQL, то там несколько по другой ветке все идет...


 
kaif   (2002-03-21 16:21) [23]

> 2 Johnmen
Ты был прав - в IBDataSet эта ошибка не проявляется. Только при использовании IBUpdateSQL. Видно поэтому на нее и не наткнулись разработчики. Я сам с IBDataSet редко работаю, но видно, это как раз тот случай, где он незаменим пока.
Ладно, перейду на IBDataSet. Пока отложу поиск ошибки. Может, разработчики сами исправят как-нибудь...

Всем спасибо.



Страницы: 1 вся ветка

Форум: "Базы";
Текущий архив: 2002.04.11;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.51 MB
Время: 0.009 c
1-32888
BAHO
2002-03-28 19:45
2002.04.11
Помогите с ListView...


3-32669
Пользователь
2002-03-20 15:08
2002.04.11
Обход всех данных в хранимой процедуре


14-32981
ATLANTIDO
2002-02-20 00:44
2002.04.11
Что такое расшарить диск?


3-32703
MaveRick
2002-03-21 04:20
2002.04.11
Есть ли возможность???


1-32896
BlackJack
2002-03-22 19:44
2002.04.11
Есть ли прога типа sourse sav-а только для delphi ?





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский