Обновите одну и ту же запись другим клиентом в SQL Server 2008 R2 - PullRequest
1 голос
/ 07 октября 2011

enter image description here

Я разрабатываю приложение в Delphi-2010 с использованием SQL Server 2008 R2 в сетевом режиме.

Моя проблема в том, что в некоторых случаях несколько клиентов открывают одну и ту же запись для обновления.
Первый клиент может обновить запись, но другие не могут, потому что SQL SERVER не может найти соответствующую запись, потому что она была изменена. Приложение должно разрешить 2 обновления без уведомления клиента.

Таблица содержит много полей, и «клиент может обновить любое из них, поскольку я не использую оператор SQL, а использую UPDATEBATCH ().

// Press UPDATE
procedure TarticleEditForm.saveButtonClick(Sender: TObject);
begin
 if (articleCode.Text <> '') AND (counter.Text <> '') AND (articleLabel.Text <> '') AND      (tbCombo.Text <> '') AND (griffeCombo.Text <> '') then begin
      ADOArticleFind.SQL.Text := 'SELECT * FROM article WHERE ID<>''' + ADOArticle.FieldByName('ID').Value + ''' AND article=''' + articleCode.Text + ''' AND mode=''' + modeCombo.Text + ''' AND counter=''' + counter.Text + '''';
      ADOArticleFind.Open;
      // UPDATE
      if ADOArticleFind.RecordCount = 0 then begin
           // SET Date Modification
           ADOArticle.FieldByName('dateModification').Value := Now;
           ADOArticle.FieldByName('modifiePar').Value := mainForm.user;
           ADOArticle.UpdateBatch();
           // Update ArticleColor/ArticleTissu tables
           ADOArticleColor.SQL.Text := 'UPDATE articleColor SET article=''' + articleCode.Text + ''', mode=''' + modeCombo.Text + ''', counter=''' + counter.Text + ''' WHERE article=''' + tmpArticleCode + ''' AND mode=''' + tmpMode + ''' AND counter=''' + tmpCounter + '''';
           ADOArticleColor.ExecSQL;
           ADOArticleTissu.SQL.Text := 'UPDATE articleTissu SET article=''' + articleCode.Text + ''', mode=''' + modeCombo.Text + ''', counter=''' + counter.Text + ''' WHERE article=''' + tmpArticleCode + ''' AND mode=''' + tmpMode + ''' AND counter=''' + tmpCounter + '''';
           ADOArticleTissu.ExecSQL;
           // create event log
           mainForm.ADOUser.SQL.Text := 'SELECT * FROM users WHERE online=1 AND editArticleEvent=1 AND username<>''' + mainForm.user + '''';
           mainForm.ADOUser.Open;
           while not mainForm.ADOUser.Recordset.EOF do begin
                mainForm.ADOMainEventLog.Insert;
                mainForm.ADOMainEventLog.FieldByName('event').Value := 'Article modifié: ' + designationCombo.Text + ' ' + saisonCombo.Text + ' ' + articleCode.Text + '-' + modeCombo.Text + counter.Text + ' de ' + griffeCombo.Text;
                mainForm.ADOMainEventLog.FieldByName('eventFrom').Value := mainForm.user;
                mainForm.ADOMainEventLog.FieldByName('eventTo').Value := mainForm.ADOUser.FieldByName('username').Value;
                mainForm.ADOMainEventLog.FieldByName('eventType').Value := 'editArticleEvent';
                mainForm.ADOMainEventLog.UpdateBatch();
                mainForm.ADOUser.Next;
           end;
           // Finish
           Self.Close;
      end
      else begin
           MessageBox(Application.Handle, 'Cet article existe déja.', 'GET© Driver', MB_ICONWARNING);
           articleCode.SetFocus;
      end;
 end
 else
      MessageBox(Application.Handle, 'Champs obligatoire(s) manquant(s).', 'GET© Driver', MB_ICONWARNING);
end;

Ответы [ 2 ]

2 голосов
/ 07 октября 2011

Поскольку вы говорите, что используете updatebatch Я предполагаю, что вы используете TADODataSet (или, возможно, TADOTable, TADOQuery).

Как ADO создает оператор обновления, контролируется свойством набора записей Update Criteria.Значение по умолчанию adCriteriaUpdCols, что означает, что в предложении обновления where сравниваются все измененные поля со старым / исходным значением.Чтобы updatebatch использовал только ключевые столбцы, вы можете сделать что-то вроде этого.

ADODataSet1.CommandText := 'select * from SomeTable';

ADODataSet1.Open;
ADODataSet1.Recordset.Properties['Update Criteria'].Value := adCriteriaKey;

ADODataSet1.Edit;
ADODataSet1.FieldByName('SomeColumn').AsString := 'New value';
ADODataSet1.Post;

ADODataSet1.UpdateBatch();

Код выше для TADOQuery будет выглядеть следующим образом.

ADOQuery1.SQL.Text := 'select * from SomeTable';

ADOQuery1.Open;
ADOQuery1.Recordset.Properties['Update Criteria'].Value := adCriteriaKey;

ADOQuery1.Edit;
ADOQuery1.FieldByName('SomeTable').AsString := 'New value';
ADOQuery1.Post;

ADOQuery1.UpdateBatch();

BTW, adCriteriaKey определено в ADOInt.pas

2 голосов
/ 07 октября 2011

Я всегда предпочитаю использовать чистый SQL, чтобы что-то происходило в базах данных, вместо того, чтобы полагаться на абстракцию базы данных в наборах данных / таблицах.

Query1.SQL.Text:= 'UPDATE table1 SET a=:newvalue WHERE A=:oldvalue';
Query1.ParamByName('newvalue').AsString:= '1';
Query1.ParamByName('oldvalue').AsString:= '2';
Query1.Prepare;
Query1.ExecSQL;

Используя такой код, вы можете установить столько одновременных обновлений SQL-сервера, сколько захотите.

...