обновление двух и более таблиц в одной транзакции

 
0
 
Delphi, Kylix & Pascal
ava
serega1983 | 02.10.2013, 12:00
Доброго времени суток.
Есть база данных Firebird.
Необходимо реализовать списание товаров со склада.
Делаю следующее.
1) создаю расходную накладную
2) заполняю ее данными из таблицы склада
3) выставляю необходимо количество товара для списания
4) жму сохранить и записи из dataSet вставляются в таблицу расходная накладная
5) со склада вычитается кол-во товара, указанное в dataSet
Проблема возникает со списанием товара со склада.

Как делаю.

Таблицы
user posted image

Форма
user posted image


FDataSet: TIBCustomDataSet;
ibQuery.cashedUpdate := true;




запрос для query

select ss.amount,
       ss.ID,
       ss.product_id,
       s.title
from sales_invoice ss
join storehouse s
    on s.id            = ss.product_id
    and ss.register_id = :idDocument
order by s.title


Последний вариант моего "мучения" был такой


procedure TForm1.Button2Click(Sender: TObject);
var Q: TIBQuery;
begin
  try
      IBTransactionWriteoffProducts.StartTransaction;
      if FDataSet.RecordCount = 0 then begin
          raise Exception.Create('Документ пуст!');
      end;

      Q := TIBQuery.Create(nil);
      Q.Transaction := IBTransactionWriteoffProducts;
      FDataSet.First;
      while not FDataSet.Eof do begin
          if(FDataSet.CachedUpdateStatus = cusInserted) then begin
              Q.Close;
              Q.SQL.Clear;
              Q.SQL.Add('update storehouse set amount = amount - :amount where id = :id and amount - :amount >= 0');
              Q.Prepare;
              Q.ParamByName('id').AsInteger   := FDataSet.FieldByName('product_id').AsInteger;
              Q.ParamByName('amount').AsFloat := FDataSet.FieldByName('amount').AsFloat;
              Q.ExecSQL;

              if(Q.RowsAffected < 1) then begin
                  raise Exception.Create('Вы пытаетесь списать товаров больше чем их есть на складе. Товар "'
                                         + FDataSet.FieldByName('title').AsString + '" кол-во ' + FDataSet.FieldByName('amount').AsString);
              end;
          end;

          FDataSet.Next;
      end;


      FDataSet.Database.ApplyUpdates([FDataSet]);
      IBTransactionWriteoffProducts.Commit;
  except
      on E : Exception do begin
          IBTransactionWriteoffProducts.Rollback;
          ShowMessage(E.ClassName + ' ошибка : ' + E.Message);
      end;
  end;
end;

списание со склада проходит успешно, а вставка в расходную не происходит - ошибка транзакция уже активна. Почему так происходит я понимаю. Как это победить - не знаю.

Ответа на форумах ни в книгах найти не смог. Подскажите как правильно работать, с точки зрения компонентов, при изменении данных, больше чем в одной таблице или правильный подход к решению таких задач, возможно здесь компонент IBUpdateSql и не нужен вовсе.
Comments (5)
ava
DYUMON | 02.10.2013, 11:20 #
если в птичке есть тригеры то кури в их сторону
ava
serega1983 | 02.10.2013, 11:26 #
Цитата (DYUMON @ 2.10.2013,  11:20)
если в птичке есть тригеры то кури в их сторону

Не используя возможности БД(тригерры, хранимые процедуры), есть варианты?
ava
Akella | 02.10.2013, 15:19 #
Цитата (serega1983 @  2.10.2013,  11:00 findReferencedText)
ошибка транзакция уже активна.

Так а зачем ты её второй раз стартуешь?

added later:
Цитата (serega1983 @  2.10.2013,  11:00 findReferencedText)
Почему так происходит я понимаю. Как это победить - не знаю.

Значит не понимаешь.

added later:
Зачем используешь механизм cashedUpdate?
ava
serega1983 | 02.10.2013, 15:50 #
Цитата (Akella @ 2.10.2013,  15:19)
Так а зачем ты её второй раз стартуешь?


FDataSet.Database.ApplyUpdates([FDataSet]);
Здесь она стартует автоматически.

Цитата (Akella @ 2.10.2013,  15:19)
Значит не понимаешь.

Не исключаем такого варианта =)

Цитата (Akella @ 2.10.2013,  15:19)
Зачем используешь механизм cashedUpdate?


Для занесения изменений в БД после нажатия кнопочки "Сохранить"

Цитата (Akella @ 2.10.2013,  15:19)
У тебя обе операции должны проходить в рамках одной активной транзакции (IBTransactionWriteoffProducts). Обе квери должны быть подключены к одной и той же  транзакции.

Все привязано к транзакции IBTransactionWriteoffProducts;






ava
serega1983 | 02.10.2013, 21:49 #
Проблема решилась сама, но скорее всего было

Цитата (Akella @  2.10.2013,  15:19 findReferencedText)
У тебя обе операции должны проходить в рамках одной активной транзакции (IBTransactionWriteoffProducts). Обе квери должны быть подключены к одной и той же  транзакции.


Всем спасибо.
Please register or login to write.
Firm of day
Вы также можете добавить свою фирму в каталог IT-фирм, и публиковать статьи, новости, вакансии и другую информацию от имени фирмы.
Подробнее
Contributors
advanced
Submit