Основная деталь с использованием ClientDataSet.AppyUpdates с отдельным DataSetProvider - PullRequest
3 голосов
/ 24 ноября 2011

Я использую два ClientDataSets для отношения master-detail с DataSetProvider для каждого CDS.Я не использую вложенные CDS для детализации, так как я выполняю фильтрацию в памяти для отношения мастер-детализация.

Проблема, с которой я сталкиваюсь, заключается в том, чтобы применить свои изменения к базовой базе данных (Жар).Для ВСТАВКИ детализации я должен сначала применить мастер, а для УДАЛЕНИЯ детали я должен сначала применить деталь (не нарушая отношения мастер-деталь в БД).Все идет нормально.Но что мне делать, если в моем CDS с мелкими деталями есть комбинация INSERT и DELETE?Тогда я не могу применить его до или после основного CDS.

Как я могу справиться с такой ситуацией, не используя вложенные CDS?

Ответы [ 3 ]

2 голосов
/ 24 ноября 2011

Обычно вы вставляете / обновляете одну основную запись, а затем работаете с деталями (вставка, обновление, удаление).Один из способов решения вашей проблемы - поместить всю операцию в транзакцию (запустить транзакцию перед внесением каких-либо изменений), вставить / обновить основную запись (отдельную запись), выполнить MasterCDS.ApplyUpdates, работать с подробными записями,сделать DetailCDS.ApplyUpdates и, наконец, зафиксировать или откатить всю транзакцию.Поскольку ваши CDS находятся в отношениях мастер / подробности, DetailCDS "увидит" записи в MasterCDS, как только они будут Post ed, и вы получите значение первичного ключа, как только вы ApplyUpdates на MasterCDS,Таким образом, вы поддерживаете ссылочную целостность (ограничения внешнего ключа) и можете делать все, что у вас есть на DetailCDS.

. Кроме того, есть события как на TClientDataSet, так и на TDataSetProvider, которые дают вам (почти)полный контроль над всем процессом, поэтому внимательно посмотрите на все доступные события.

ПРИМЕЧАНИЕ: я могу ошибаться в некоторых деталях, поскольку я объясняю это из своей памяти, но идея важна.Поэкспериментируйте немного, и вы найдете решение.

0 голосов
/ 26 ноября 2011

При использовании отдельных поставщиков наборов данных я обнаружил, что обновления в каждом DSP выполнялись в отдельной транзакции (по крайней мере, в Interbase).Меня это не беспокоило, но ваше приложение может требовать согласованности всех наборов данных.

0 голосов
/ 24 ноября 2011

Я бы применил мастера, а затем детали.

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

Когда вы удаляете детали, вам снова нужно будет переопределить BeforeApplyUpdates. Если основная запись отсутствует, не пытайтесь выполнить удаление.

Вы можете «пропустить» удаление подробных записей, используя пользовательскую команду обновления. Единственная причина сделать это, чтобы остановить datasnap генерировать саму команду SQL, а затем потерпеть неудачу, потому что строки пострадали = 0. Я бы вероятно использовал что-то вроде

IF EXISTS (SELECT * FROM dbo.ParentTable WHERE ParentKey = @ParentKey)
BEGIN
  DECLARE @rowcount INT
  DELETE
    FROM dbo.ChildTable
    WHERE ChildKey = @ChildKey
  SET @rowcount = @@ROWCOUNT
  IF @rowcount <> 1
  BEGIN
    RAISERROR('Record not found.(%d)', 15, 1, @rowcount) WITH SETERROR
  END
END

Затем в событии BeforeUpdateRecord вы вызываете эту команду

case UpdateStatus of
  ukDelete:
    begin
      sqlDeleteChild.Parameters.ParamByName('@ChildKey').Value := DeltaDS.FieldByName('ChildKey').OldValue;
      sqlDeleteChild.Parameters.ParamByName('@ParentKey').Value := DeltaDS.FieldByName('ParentKey').OldValue;
      sqlDeleteChild.Execute;
    end;
  ...
end;
Applied := true;
...