-
В трехзвенке С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?
Спасибо.
-
Или вопрос задал плохо, или лыжи не едут...
-
ADOQuery.ExecuteOptions = ?
-
По умолчанию, по всей видимости, ADOQuery.ExecuteOptions = []... Игрался наугад с eoAsyncExecute, eoAsyncFetch, eoAsyncFetchNonBlocking, eoExecuteNoRecords... При eoAsyncExecute получил ошибку EOleException 'Текущий проводник не поддерживает асинхронное выполнение'. При использование других опций ничего особенного не происходило. Где копать?
-
Где и как у тебя осуществляется управление транзакциями ?
-
> Где и как у тебя осуществляется управление транзакциями
> ?
Интересный вопрос... Все делается само собой, тобиш по дефолту. Пытался делать так
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....
-
Приводи код работы в контексте читающей транзакции, той самой к которой относится "клиент перечитывает таблицу qualref" ..
-
Не понял...
Клиентское приложение, например, имеет кнопку 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 со стороны сервера. Как привести этот код в контексте читающей транзакции? Может я чего не понял? Заранее извиняюсь...
-
Если пишу так
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) не успевает.
-
Приводи код RefreshListView
-
Чтобы не приводить код 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) решить эту задачу?
-
Мне непонятно, почему IServer имеет метод для модификации, но не имеет метода для выборки.
Или такой метод все же есть ? Если есть, то почему его не используешь ?
-
Для выборки использую связку компонентов ClientDataSet1 (со стороны клиента), ADOQuery1 и DataSetProvider1 (со стороны сервера). Тоесть использую технологию MIDAS (или DataSnap) в чистом виде.
Как можно передать DataSet без MIDAS не знаю... Но это уже другой вопрос.
-
> Для выборки .. использую технологию MIDAS (или DataSnap) в чистом виде
Это понятно.
Непонятно почему не использовать ту же технологию (соотв-но, тот же App-сервер в том же сеансе и, возможно, в той же ТА) для модифицирующих акций..
Т.е. чем обусловлена эта "солянка сборная" из MIDAS-сервера для выборки и IServer COM-сервера для модификации ..
-
> чем обусловлена эта "солянка сборная" из MIDAS-сервера для
> выборки и IServer COM-сервера для модификации ..
Хотел "ручками" написать COM-сервер. С передачей DataSet не разобрался (скорее поленился разбираться). Вот такой гибридный сервер и получился...
В связи с этим у меня 2 вопроса:
1) Эсли все оставить как есть ("солянка сборная"), то проблема рефреша DBGrid не решается? И дело тут не в TADOQuery.ExecSQL, как это звучит в теме вопроса?
2) Эсли отбросить MIDAS, как написать метод интерфейса IServer для выборки? Тоесть каким образом передавать DataSet? Подозреваю, что нужно использовать вариант-массив, если передававать DataSet построчно, или двухмерный вариант-массив, если передававать DataSet целиком.
Буду очень признателен за ответы.
-
> чем обусловлена эта "солянка сборная" из MIDAS-сервера для
> выборки и IServer COM-сервера для модификации ..
Хотел "ручками" написать COM-сервер. С передачей DataSet не разобрался (скорее поленился разбираться). Вот такой гибридный сервер и получился...
В связи с этим у меня 2 вопроса:
1) Эсли все оставить как есть ("солянка сборная"), то проблема рефреша DBGrid не решается? И дело тут не в TADOQuery.ExecSQL, как это звучит в теме вопроса?
2) Эсли отбросить MIDAS, как написать метод интерфейса IServer для выборки? Тоесть каким образом передавать DataSet? Подозреваю, что нужно использовать вариант-массив, если передававать DataSet построчно, или двухмерный вариант-массив, если передававать DataSet целиком.
Буду очень признателен за ответы.
-
Ты для начала одно скажи - объект, реализующий IServer, он твоей разработки ? МИДАС-сервер - тоже твоей ?
-
Все мое. Делал так:
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. Большое спасибо.
Если можно, по второму вопросу очень интересно узнать правильное решение.
-
> по второму вопросу очень интересно узнать правильное решение
Ну что-то вроде этого:
function TrdmServer.GetLinks: OleVariant;
begin
with TClientDataSet.Create(..) do
try
.. здесь временно созданный объект ClientDataSet связывается с конкретным провайдером, поставляющим требуемый НД
Result := DataRequest(..параметры формирования НД ..);
finally
free
end;
end;
...
MyClientDataSet := Server.GetLinks;
-
Большое спасибо за ответ. Все работает. Только 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? Есть ли в этом случае принципиальная разница?