Мой ClientDataSet.ApplyUpdates не публикуется в моей таблице базы данных MySQL?

Мне интересно, почему данные, размещенные в моем наборе клиентских данных, не обновляются в таблице базы данных MySQL с помощью ApplyUpdates.

Я работаю над 2 базами данных.

  1. DB1.CustomerTable1: нет проблем, первичный ключ в «ListID» —> CDS.Append —> CDS.ApplyUpdates

  2. DB2.CustomerTable2: с проблемой, первичный ключ в 'Guid' —> CDS.Edit —> CDS.ApplyUpdates.

Я добавил первичный ключ в DB2.CustomerTable2 с «ListID» и все еще не работает.

Ниже коды, с которыми я работаю.

procedure TfrmMain.spbExportClick(Sender: TObject);
var
  Guid , VarAccountId, VarListSasId, VarListDspId : Variant;
  Status : String;
begin
  with dm.dmForm do
  begin
    cdsCustomer2.first;
    while not cdsCustomer2.eof do
    begin

      //variable data for CDS.Customer1.AllFields
      Guid := cdsCustomer2.FieldByName ('Guid').AsString;
      VarAccountId := cdsCustomer2.FieldByName('ListID').AsString;
      VarListSasId := cdsCustomer2.FieldByName('FullName').AsString;
      VarListDspId := cdsCustomer2.FieldByName('Name').AsString;
      Status := 'Out';

      //posting to CDS.Customer1.AllFields
      cdsCustomer1.DisableControls;
      cdsCustomer1.Append;
      cdsCustomer1.FieldByName('GUID').AsString := Guid;
      cdsCustomer1.FieldByName('AccountId').AsString := VarAccountId;
      cdsCustomer1.FieldByName('ListSasID').AsString := VarListSasId;
      cdsCustomer1.FieldByName('ListDspID').AsString := VarListDspId;
      cdsCustomer1.FieldByName('Status').AsString := Status;
      cdsCustomer1.EnableControls;
      cdsCustomer1.Fields[1].ProviderFlags := [pfInKey];
      cdsCustomer1.Post;

      //posting Guid value back to CDS.Customer2
      if cdsCustomer2.locate('ListID', VarAccountId, [])  then
      begin
        cdsCustomer2.DisableControls;
        cdsCustomer2.Edit;
        cdsCustomer2.FieldByName('ExternalGUID').AsString := Guid;
        cdsCustomer2.EnableControls;
        cdsCustomer2.Fields[0].ProviderFlags := [pfInKey];
        cdsCustomer2.Post;
      end;

      cdsCustomer2.Next;
    end;

    //ApplyUpdates to mysql Customer1.Table and Customer2.Table
    cdsCustomer1.ApplyUpdates(-1);
    cdsCustomer2.ApplyUpdates(-1);

  end;
end;

Я ожидаю, что эти коды будут просто публиковаться в моей базе данных MySQL2 точно так же, как и в базе данных 1. Все работает вплоть до публикации в оба набора ClientDataSet, кроме публикации cdsCustomer2 из DB2.

Дайте мне знать, если я пропустил какую-то информацию, которая может вам понадобиться.

P.S. Вот, кстати, структура базы данных: UniConnection -> MySQLUniProvider -> UniQuery -> DataSetProvider -> ClientDataSet -> DataSource -> DBGrid

Вызов cdsCustomer2.locate выглядит излишним, учитывая, что значение ключа берется из текущей записи ранее. Также комментарий перед вызовом DisableControls выглядит не связанным с фактическим кодом.

Uwe Raabe 13.05.2019 09:55

@UweRaabe Спасибо. Извиняюсь за путаницу.

Mel 13.05.2019 13:28
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
В последние годы архитектура микросервисов приобрела популярность как способ построения масштабируемых и гибких приложений. Laravel , популярный PHP...
Как построить CRUD-приложение в Laravel
Как построить CRUD-приложение в Laravel
Laravel - это популярный PHP-фреймворк, который позволяет быстро и легко создавать веб-приложения. Одной из наиболее распространенных задач в...
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
В предыдущем посте мы создали функциональность вставки и чтения для нашей динамической СУБД. В этом посте мы собираемся реализовать функции обновления...
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
Роли и разрешения пользователей без пакета Laravel 9
Роли и разрешения пользователей без пакета Laravel 9
Этот пост изначально был опубликован на techsolutionstuff.com .
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
В предыдущей статье мы завершили установку базы данных, для тех, кто не знает.
1
2
188
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Диагностика проблем с ApplyUpdates может быть немного утомительной, потому что иногда это вопрос перебора нескольких возможностей, пока вы не найдете тот, который применим к вашей ситуации, поэтому я не могу сказать вам «просто сделайте это ...», и это исправит твоя проблема.

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

  • Ваши звонки в ApplyUpdates

    cdsCustomer1.ApplyUpdates(-1);
    cdsCustomer2.ApplyUpdates(-1);
    

Измените это на

  var Count : Integer;
  [...]
  Count := cdsCustomer1.ApplyUpdates(0);
  Assert(Count = 0);
  Count := cdsCustomer2.ApplyUpdates(0);
  Assert(Count = 0);

Дело в том, что указание -1 в качестве аргумента для ApplyUpdates делает прямо противоположное тому, что вы хотите, т.е. допускает любое количество ошибок для создания в процессе ApplyUpdates. Вы хотите, чтобы это останавливаться при любой ошибке, что и будет делать 0, чтобы вы могли узнать какая ошибка возвращается во время ApplyUpdates.

Также

  • Когда вы обновляете cdsCustomer2, вы по ошибке звоните cdsCustomer1.DisableControls вместо cdsCustomer2.DisableControls. В нынешнем виде эта ошибка будет препятствовать правильному отображению cdsCustomer1 впоследствии.

Внесите эти изменения, скомпилируйте и запустите свое приложение и, возможно, одно из двух Count := [...] выдаст вам сообщение об исключении, которое идентифицирует причина вашей проблемы. Если это не так:

  • Убедитесь, что на вашем сервере для обеих таблиц определен первичный ключ, и затем убедитесь, что в правильных полях ваших CDS указан поставщик pfInkey набор флагов. Если это сработает, попробуйте установить для них значение pfInWhere.

  • В исходном файле VCL Provider.Pas найдите процедуру

процедура TSQLResolver.InternalDoUpdate(Tree: TUpdateTree; UpdateKind: TUpdateKind);

Его последняя строка должна быть

DoExecSQL(FSQL, FParams);

Поставьте на него точку останова, запустите ваше приложение, и когда оно остановится на БП, оцените FSQL и посмотрите, правильно ли он выглядит. Если это так, попробуйте выполнить тот же SQL из любой утилиты MySql, которую вы используете для работы с вашим сервером.

Как обычно, я ценю ваш очень подробный ответ. Я исправил ошибку cdsCustomer2.DisableControls на cdsCustomer1.DisableControls. С другой стороны, я смог разобраться в проблеме. Я упомянул о 2 базах данных, с которыми я работаю. В моем модуле данных у меня есть только одна база данных TUniConnection, и она предназначена для cdsCustomer1. У меня нет TUniConnection для другой базы данных, предназначенной для cdsCustomer2.

Mel 13.05.2019 13:49

Но что более удивительно, я смог прочитать данные таблицы для cdsCustomer2 при отсутствии его базы данных TUniConnection. За исключением уровня редактирования, который был моей главной проблемой. После создания отдельного TUniConnection я смог отправить данные в DB2.CustomerTable2.

Mel 13.05.2019 13:50

Что касается ApplyUpdates, я просто хочу знать, является ли это стандартным кодированием, которое я буду использовать в будущем, или только в этом случае. Прямо сейчас я разделил 2 ApplyUpdates и прикрепил их сразу после каждого сообщения?

Mel 13.05.2019 13:55

Вам решать, будете ли вы вызывать .ApplyUpdates после каждого .Post, в зависимости от требований к целостности данных вашего приложения - откладывание их рискует, а также сильно раздражает ваших пользователей, если они не узнают сразу, если обновления не могут быть применены. .

MartynA 13.05.2019 17:15

Кстати, @MartynA, я уже изменил на 0 вместо -1. Я просто немного смущен, если после разделения я все еще буду делать это Count := cdsCustomer1.ApplyUpdates(0); Утвердить (Количество = 0);?

Mel 13.05.2019 22:59

Строго говоря, вам не нужна Assert(), но полезно привлечь ваше внимание, если есть проблема.

MartynA 13.05.2019 23:04

Добавьте исключение повышения в OnUpdateError DataSetProvider — по умолчанию исключения молчат, чего я никогда не понимал. Итак, что-то вроде Raise Exception (E.Message) - вы можете обнаружить, что пытаетесь обнулить поле, которое должно быть ненулевым или подобным.

Ответ принят как подходящий

После воспроизведения этого случая, чтобы определить, откуда именно исходит ошибка. Я понял, что не создал соединение для другой базы данных. Таким образом, решение для этого случая состоит в том, чтобы создать соединения для каждой базы данных, чтобы беспрепятственно взаимодействовать с двумя базами данных.

Чтобы проиллюстрировать это, вот подключение, которое у меня есть сейчас, и я пока не получаю никаких ошибок при синхронизации двух баз данных:

Database1 —> TUniConnection1 —> MySQLUniProvider1 —> TUniQuery1 —> TDataSetProvider1 —> TClientDataSet1 —> TDataSource1 —> TDBGrid1

Database2 —> TUniConnection2 —> MySQLUniProvider2 —> TUniQuery2 —> TDataSetProvider2 —> TClientDataSet2 —> TDataSource2 —> TDBGrid2

Я не уверен, есть ли лучший способ управлять несколькими подключениями к базе данных одновременно в проекте. Но это работает для меня.

Другие вопросы по теме