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

Вниз

SQL update в одной транзакции   Найти похожие ветки 

 
Empleado   (2003-05-27 12:19) [0]

День добрый,
возник вопрос по SQL апдейт (ADO): как осуществить СКЛ апдейт нескольких таблиц в рамках одной транзакции?

Используются: трехзвенка, на сервере-АДО Коннекшин с СКЛ2000, АДО Датасет, Датасетпровайдер.
Когда с клиента приходит запрос, на Датасетпровайдер.BeforeUpdateRecord смотрим, если запись удаляется, то замещаем эту операцию операцией логического удаления, т.е. надо заапдейтить все записи, соответствующие удаляемой, во всех таблицах, связанных с исходной (в которой происходит удаление), и изменить поле LD (LogicallyDeleted) на True.
Список таблиц и порядок их обновления есть. Получить СКЛ строку АПДЕЙТ тоже не трудно.
Но как это организовать так, чтобы крах изменений в одной таблице приводил к откату всех уже сделанных изменений, в данной схеме и с АДО - не пойму.

Ани хелп из апприсиэйтд. Нагляднее конечно же с примером или ссылочкой.
Спасибо
Empleado (ex.Niki)


 
Polevi   (2003-05-27 12:31) [1]

raise должен откатить транзакцию
и посмотри как реализует IProviderSupport TAdoDataset и вызовы методов этого интефейса в provider.pas


 
Empleado   (2003-05-27 17:00) [2]

У меня проявляется явное несоответствие моего объема знаний и затронутой темы.
Собственно говоря, апдейт работает. Вот процедура в которой вся эта каша варится:

procedure TNothingRDM.DSP_BeforeUpdateRecord(Sender: TObject;
SourceDS: TDataSet; DeltaDS: TCustomClientDataSet;
UpdateKind: TUpdateKind; var Applied: Boolean);
var Lst: TStringList;
pk: integer;
ws: WideString;
begin
{This is a procedure used for all DataSetProviders for BeforeUpdateRecord event}
{If there is an insert action then it adds a PK value in the Delta because of his absence.
That is: a client adds a record but he cannot obtain this value immediately in some reasons.
At the server side the program does this change and applies the Delta to the DB server directly (ResolveToDataSet=False).
If there is a delete action then it marks all records as "deleted" to not have it deleted physically
and propagate his "removing" across all tabels bound with integrated relationship}
case UpdateKind of
ukInsert: begin
if SourceDS = adsPersons then SetPKValue(DeltaDS, "Persons", "IDPerson");
if SourceDS = adsCars then SetPKValue(DeltaDS, "Cars", "IDCar");
if (SourceDS = adsPersonCar) or (SourceDS = adsCarPerson) then SetPKValue(DeltaDS, "PersonCar", "IDPersonCar")
end; {ukInsert}
ukDelete: begin {Replace "Delete" action by modification of "DeletedLogically" field}
{Get tables" names to be updated, corresponding fields" names
for searching in these tables and the key value}
Lst := TStringList.Create;
{Lst format: First string is a table name, following one is a field name, etc.}
try
if GetDataToUpdate(SourceDS, DeltaDS, Lst, pk) then
if Lst.Count >= 2 then begin
ws := GetUpdateLDCommandText(Lst, pk);
if ws <> "" then ConnNothing.Execute(ws)
else raise Exception.Create("DSP_BeforeUpdateRecord on SourceDS="" + SourceDS.Name + "" : SQL Command text is empty");
Applied := True
end
else raise Exception.Create("DSP_BeforeUpdateRecord on SourceDS="" + SourceDS.Name + "" : Items count in the string list is less then "2"")
else raise Exception.Create("DSP_BeforeUpdateRecord on SourceDS="" + SourceDS.Name + "" : Error occurred in "GetDataToUpdate"")
except
Lst.Free;
raise {to see on a client which error is occurred}
end;
Lst.Free
end {ukDelete}
end {case}
end;

ConnNothing: TADOConnection

А вот СКЛ апдейт, только что прогнанный:

UPDATE PersonCar SET LD="1" WHERE IDPersonCar="8" UPDATE PersonCar SET LD="1" WHERE IDPersonCar="9" UPDATE PersonCar SET LD="1" WHERE IDPersonCar="10" UPDATE PersonCar SET LD="1" WHERE IDPersonCar="12"
UPDATE Persons SET LD="1" WHERE IDPerson="12"

Таблицы:
Persons -люди
Cars -машинки
PersonCar -скока машинок у людев и наоборот

Но вот завернуть этот апдейт в BeginTrans-CommitTrans у меня не получается. У меня три апдейта в одном стэйтменте. Может надо их разбить на три разных Execute("UPDATE...")?


 
Empleado   (2003-05-27 17:07) [3]

Ужас, что получилось, процедура без комментариев:

procedure TNothingRDM.DSP_BeforeUpdateRecord(Sender: TObject;
SourceDS: TDataSet; DeltaDS: TCustomClientDataSet;
UpdateKind: TUpdateKind; var Applied: Boolean);
var Lst: TStringList;
pk: integer;
ws: WideString;
begin
case UpdateKind of

ukInsert: begin
if SourceDS = adsPersons then SetPKValue(DeltaDS, "Persons", "IDPerson");
if SourceDS = adsCars then SetPKValue(DeltaDS, "Cars", "IDCar");
if (SourceDS = adsPersonCar) or (SourceDS = adsCarPerson) then SetPKValue(DeltaDS, "PersonCar", "IDPersonCar")
end; {ukInsert}

ukDelete: begin
Lst := TStringList.Create;
{Lst format: First string is a table name, following one is a field name, etc.}
try
if GetDataToUpdate(SourceDS, DeltaDS, Lst, pk) then
if Lst.Count >= 2 then begin
ws := GetUpdateLDCommandText(Lst, pk);
if ws <> "" then ConnNothing.Execute(ws)
else raise Exception.Create("SQL Command text is empty");
Applied := True
end
else raise Exception.Create("Items count in the string list is less then "2"")
else raise Exception.Create("Error occurred in "GetDataToUpdate"")
except
Lst.Free;
raise {to see on a client which error is occurred}
end;
Lst.Free
end {ukDelete}
end {case}
end;



 
Polevi   (2003-05-27 17:57) [4]

если бы та заглянул в исходники..
вообщем если ты в данной процедуре сделаешь любой raise и у тебя не обрабатывается OnUpdateError - провайдер сам сделает Rollback


 
Empleado   (2003-05-28 13:56) [5]

>Polevi © (27.05.03 17:57)

Так-то оно так, дык я же не использую ДатаСетПровайдер для обновлений в БД в случае удаления.
В данном случае (в приведенной процедуре) юзаю TADOConnection.Execute("SQL update string") из ДатаСетПровайдер.BeforeUpdateRecord.
Естесссно этому апдейту по барабану все разногласия в записях, когда одну запись поочередно меняют несколько юзеров, меня это устраивает, т.к. это операция удаления, и он не приведет к ReconcileError.
НО, если есть ошибка в "SQL update string", напр, неверно имя тавлицы, или поля, то выполнение апдейта приостанавливается.
A если изменения уже были успешно проведены на двух таблицах, а на третьей спотыкнулись? (e.g. "SQL update string"="UPDATE T1 SET... UPDATE T2 SET... UPDATE T3 SET..." <-- error после "UPDATE T3 SET...")
Хотелось бы их роллнуть взад на всех таблицах вместе. Как быть в таком случае?
Наставьте на путь истинный, а?

>All
Может кто-то поделится своими мыслями о реализации логического удаления записей? Как вы это делали в своих проектах?

Gracias


 
Empleado   (2003-05-30 12:33) [6]

ап


 
Danilka   (2003-05-30 12:54) [7]

Сходи на sql.ru, на форум по MS SQL:
http://www.sql.ru/forum/actualtopics.aspx?bid=1

Вообще-то я с MS SQL ниразу не работал, случайно на их форум зашел, там было обсуждение, что в этом серваке старт и завершение транзакций правильнее всего делать в ХП, и очень неправльно - с клиента. Для меня это звучит дико, поэтому я не могу на основе своего опыта сказать что-то путное. Вобщем, попробуй задать свой вопрос там.


 
Empleado   (2003-05-30 13:26) [8]

>Danilka © (30.05.03 12:54)
спасибо

Да я бы с дикой радостью делал бы это в ХП, un problema в том, что необходимо сделать сервер как можно более независимым от типа бд. Знаю, что это гемор. Народ хочет, чтобы это работало и под Парадокс и под МойСКЛ и т.д.


 
Empleado   (2003-06-02 11:22) [9]

ап
"...Но вот завернуть этот апдейт в BeginTrans-CommitTrans у меня не получается..."



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

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

Наверх





Память: 0.48 MB
Время: 0.027 c
14-84611
Sergey13
2003-06-09 10:34
2003.06.26
Я балдею от такой наглости!!! Куда смотрит милиция?


8-84456
Zakus
2003-01-14 17:12
2003.06.26
TImage - Чтобы не мелькал


14-84597
Vlad Oshin
2003-06-09 09:17
2003.06.26
:) (=============чтоб попасть было легче..:)


3-83926
GSVSerg
2003-06-03 18:34
2003.06.26
CheckBox в DBGrid


14-84605
kaif
2003-06-07 01:55
2003.06.26
Вопрос к материалистам





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский