Конференция "Corba" » Как дождаться завершения работы TADOQuery.ExecSQL [Delphi, Windows]
 
  • yuray (24.07.07 13:30) [0]
    В трехзвенке СOM-клиент вызывает процедуру AddLink COM-сервера для вставки записи в таблицу MS Access

    procedure TrdmServer.AddLink(Sem_ID: Integer; Ref_ID: Integer; out Mess: OleVariant);
    begin
     with TADOQuery.Create(self) do
     try
       Connection:=ADOConnection1;
       SQL.Add('insert into qualref (sem_id, ref_id) values (:sem_id,  :ref_id)');
       Parameters[0].Value:=Sem_ID;
       Parameters[1].Value:=Ref_ID;
       ExecSQL;
       //sleep(1000); //это решает проблему
       Mess:='ok';
     finally
       free
     end;
    end;

    После этого клиент перечитывает таблицу qualref, но необходимой записи не находит. Вставка происходит с запозданием. Если ставлю sleep(1000); на сервере или клиенте, то все работает. Как можно "правильно" дождаться завершения работы ExecSQL?  

    Спасибо.
  • yuray (20.08.07 23:41) [1]
    Или вопрос задал плохо, или лыжи не едут...
  • Сергей М. © (21.08.07 11:08) [2]
    ADOQuery.ExecuteOptions = ?
  • yuray © (21.08.07 12:49) [3]
    По умолчанию, по всей видимости, ADOQuery.ExecuteOptions = []... Игрался наугад с eoAsyncExecute, eoAsyncFetch, eoAsyncFetchNonBlocking, eoExecuteNoRecords... При eoAsyncExecute получил ошибку EOleException 'Текущий проводник не поддерживает асинхронное выполнение'. При использование других опций ничего особенного не происходило. Где копать?
  • Сергей М. © (21.08.07 13:21) [4]
    Где и как у тебя осуществляется управление транзакциями ?
  • yuray © (21.08.07 13:55) [5]

    > Где и как у тебя осуществляется управление транзакциями
    > ?

    Интересный вопрос...  Все делается само собой, тобиш по дефолту. Пытался делать так

    procedure TrdmServer.DelLink(Sem_ID: Integer; Ref_ID: Integer);
    begin
     ADOConnection1.BeginTrans;
     try
       with TADOQuery.Create(self) do
       try
         Connection:=ADOConnection1;
         ExecuteOptions :=[eoAsyncFetchNonBlocking];
         SQL.Add('delete from qualref where sem_id=:sem_id and ref_id=:ref_id');
         Parameters[0].Value:=Sem_ID;
         Parameters[1].Value:=Ref_ID;
         ExecSQL;
       finally
         free;
       end;
       ADOConnection1.CommitTrans;
     except
       ADOConnection1.RollbackTrans;
     end;
    end;

    Результат тот же...
    Может с ADOConnection1 поработать? Сейчас стоит IsolationLevel=ilReadCommitted; Mode=cmReadWrite; CursorLocation=clUseClient; CommandTimeout=30....
  • Сергей М. © (21.08.07 14:31) [6]
    Приводи код работы в контексте читающей транзакции, той самой к которой относится "клиент перечитывает таблицу qualref" ..
  • yuray © (21.08.07 15:28) [7]
    Не понял...
    Клиентское приложение, например, имеет кнопку c таким обработчиком клика

    procedure TfmClient.BitBtn1Click(Sender: TObject);
    var
     ss:variant;
     Server: IServer;
    begin
     Server:=CreateRemoteComObject(CompName, CLASS_Server) as IServer;
     Server.AddLink(1, 2, ss); // Добавляем запись в таблицу qualref  
     RefreshListView;
    end;

    Процедура RefreshListView перечитывает таблицу qualref (ClientDataSet.Open) и заполняет ListView. Эта процедура работает через ClientDataSet со стороны клиента, и ADOQuery, DataSetProvider со стороны сервера. Как привести этот код в контексте читающей транзакции? Может я чего не понял? Заранее извиняюсь...
  • yuray © (21.08.07 15:32) [8]
    Если пишу так

    procedure TfmClient.BitBtn1Click(Sender: TObject);
    var
    ss:variant;
    Server: IServer;
    begin
    Server:=CreateRemoteComObject(CompName, CLASS_Server) as IServer;
    Server.AddLink(1, 2, ss); // Добавляем запись в таблицу qualref  
    Sleep(1000);////////////////////////////////////////////////////////
    RefreshListView;
    end;

    то ListView рефрешится нормально, а при Sleep(<500) не успевает.
  • Сергей М. © (22.08.07 08:12) [9]
    Приводи код RefreshListView
  • yuray © (22.08.07 12:53) [10]
    Чтобы не приводить код RefreshListView, упростим задачу.

    Клиент состоит из формы fmClient на которой расположены только кнопка BitBtn1 и DBGrid1. Бросаю на форму DCOMConnection1, ClientDataSet1 и связываю DBGrid1 и ClientDataSet1 через DataSource1. ClientDataSet1.ProviderName=DataSetProvider1.

    На стороне сервера есть ADOConnection1, ADOQuery1 и DataSetProvider1.
    ADOQuery1.SQL.Text ='select * from qualref';
    DataSetProvider1.DataSet=ADOQuery1.

    Когда жму на кнопку BitBtn1 хочу:
    1. Вставить запись в таблицу qualref.
    2. Чтобы DBGrid1 отобразила новую запись.

    procedure TfmClient.BitBtn1Click(Sender: TObject);
    var
     ss:variant;
     Server: IServer;
    begin
     Server:=CreateRemoteComObject('localhost', CLASS_Server) as IServer;
     Server.AddLink(1, 2, ss); // Добавляем запись в таблицу qualref  
     //Sleep(1000); это решает проблему
     ClientDataSet1.close;
     ClientDataSet1.Open;
    end;

    Как правильно (без sleep) решить эту задачу?
  • Сергей М. © (22.08.07 13:07) [11]
    Мне непонятно, почему IServer имеет метод для модификации, но не имеет метода для выборки.

    Или такой метод все же есть ? Если есть, то почему его не используешь ?
  • yuray © (22.08.07 13:47) [12]
    Для выборки использую связку компонентов ClientDataSet1 (со стороны клиента), ADOQuery1 и DataSetProvider1 (со стороны сервера). Тоесть использую технологию MIDAS (или DataSnap) в чистом виде.
    Как можно передать DataSet без MIDAS не знаю... Но это уже другой вопрос.
  • Сергей М. © (22.08.07 15:14) [13]

    > Для выборки .. использую технологию MIDAS (или DataSnap) в чистом виде


    Это понятно.

    Непонятно почему не использовать ту же технологию (соотв-но, тот же App-сервер в том же сеансе и, возможно, в той же ТА) для модифицирующих акций..

    Т.е. чем обусловлена эта "солянка сборная" из MIDAS-сервера для выборки и IServer COM-сервера для модификации ..
  • yuray © (22.08.07 16:00) [14]

    > чем обусловлена эта "солянка сборная" из MIDAS-сервера для
    > выборки и IServer COM-сервера для модификации ..


    Хотел "ручками" написать COM-сервер. С передачей DataSet не разобрался (скорее поленился разбираться). Вот такой гибридный сервер и получился...
    В связи с этим у меня 2 вопроса:

    1) Эсли все оставить как есть ("солянка сборная"), то проблема рефреша DBGrid не решается? И дело тут не в TADOQuery.ExecSQL, как это звучит в теме вопроса?

    2) Эсли отбросить MIDAS, как написать метод интерфейса IServer для выборки? Тоесть каким образом передавать DataSet? Подозреваю, что нужно использовать вариант-массив, если передававать DataSet построчно, или двухмерный вариант-массив, если передававать DataSet целиком.

    Буду очень признателен за ответы.
  • yuray © (22.08.07 16:00) [15]

    > чем обусловлена эта "солянка сборная" из MIDAS-сервера для
    > выборки и IServer COM-сервера для модификации ..


    Хотел "ручками" написать COM-сервер. С передачей DataSet не разобрался (скорее поленился разбираться). Вот такой гибридный сервер и получился...
    В связи с этим у меня 2 вопроса:

    1) Эсли все оставить как есть ("солянка сборная"), то проблема рефреша DBGrid не решается? И дело тут не в TADOQuery.ExecSQL, как это звучит в теме вопроса?

    2) Эсли отбросить MIDAS, как написать метод интерфейса IServer для выборки? Тоесть каким образом передавать DataSet? Подозреваю, что нужно использовать вариант-массив, если передававать DataSet построчно, или двухмерный вариант-массив, если передававать DataSet целиком.

    Буду очень признателен за ответы.
  • Сергей М. © (22.08.07 16:44) [16]
    Ты для начала одно скажи - объект, реализующий IServer, он твоей разработки ? МИДАС-сервер - тоже твоей ?
  • yuray © (22.08.07 18:15) [17]
    Все мое. Делал так:
    1. File -> New -> Application.
    2. File -> New -> Other... -> Multitier -> Remote Data Module.
    3. CoClass Name обозвал Server, а интерфейс получился IServer.
    4. К IServer добавил метод AddLink....
    5. .....

    Да... Основной вопрос решил.

    Просто нужно выбросить создание еще одного екземпляра COM-сервера, типа
    Server:=CreateRemoteComObject('localhost', CLASS_Server) as IServer, а работать с одним;

    procedure TfmClient.BitBtn1Click(Sender: TObject);
    begin
     DCOMConnection1.AppServer.AddLink(1, 2, ss);
     ClientDataSet1.Refresh;
    end;

    Все рефрешится нормально. Действительно, дело было не в TADOQuery.ExecSQL. Большое спасибо.  

    Если можно, по второму вопросу очень интересно узнать правильное решение.
  • Сергей М. © (23.08.07 09:19) [18]

    > по второму вопросу очень интересно узнать правильное решение


    Ну что-то вроде этого:

    function TrdmServer.GetLinks: OleVariant;
    begin
    with TClientDataSet.Create(..) do
    try

      .. здесь временно созданный объект ClientDataSet связывается с конкретным провайдером, поставляющим требуемый НД
     
      Result := DataRequest(..параметры формирования НД ..);
    finally
      free
    end;
    end;

    ...

    MyClientDataSet := Server.GetLinks;
  • yuray © (23.08.07 13:57) [19]
    Большое спасибо за ответ. Все работает. Только GetLinks написал как процедуру с использованием ТADOQuery.

    procedure TrdmServer.GetLinks(out Data: OleVariant);
    begin
      ADOQuery1.Open;
      Data:=DataSetProvider1.Data;
      ADOQuery1.Close;
    end;

    На клиенте работаю так

    procedure TfmClient.BitBtn1Click(Sender: TObject);
    var
      data:OleVariant;
    begin
      Server.GetLinks2(data);
      MyClientDataSet.Data := data;
    end;

    Так правильно или все же нужно через TClientDataSet? Есть ли в этом случае принципиальная разница?
 
Конференция "Corba" » Как дождаться завершения работы TADOQuery.ExecSQL [Delphi, Windows]
Есть новые Нет новых   [120350   +22][b:0][p:0.006]