Форум: "Базы";
Текущий архив: 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.026 c