Apenas 1 SQLConnection na aplicação Servidora, como faço?

Delphi

17/05/2005

Fala galera!!...seguinte: como faço para ter apenas 1 SQLConnection na minha aplicação servidora?...para depois na aplicação cliente ter apenas 1
SocketConnection?...Explicando melhor, numa aplicação cliente/servidor, isto é facil, basta ter um datamodule central e adicionar nele um componente de conexão (como SQLConnection)...e depois os demais datamodules conterão as queryes ligadas ao dm central. Agora queria saber como faço para organizar os componentes nesse sentido para uma aplicação multicamadas. Fui aconselhado a ter em cada Remote Data Module que criar, ter um componente SQLConnection, mas e depois na aplicação cliente?....vai ficar ruim pois tb terei que ter um SocketConnection para cada SQLConnection....queria fazer algo que seguisse o mesmo modelo da aplicação cliente/servidor..ou seja, centralizar os componentes de conexão.

se alguém puder me ajudar!!....brigadão!!!

T++ pessoal

Marcelo


Tchelllo

Tchelllo

Curtidas 0

Respostas

Cristiam

Cristiam

17/05/2005

Crie uma classe para fazer isso. ;)


GOSTEI 0
Tchelllo

Tchelllo

17/05/2005

Olá Cristiam....será que vc pode ser mais detalhado ?....a classe que vc diz seria criar outro Remote Data Module e colocar no uses o RDM principal que contem o SQLConnection?....pois se for, na aplicação cliente como faço para enxergar o RDM que contem as DataSets?

vlwww!!


GOSTEI 0
Kotho

Kotho

17/05/2005

dá uma olhada neste tópico [url]http://forum.clubedelphi.net/viewtopic.php?t=42509[/url]


GOSTEI 0
Tchelllo

Tchelllo

17/05/2005

Olá Kotho....analisei seu forum...mas não entendi algumas passagens...como por ex.

function TRDM.Get_RDMRelatorio: IRDMRelatorio;
begin
Result := RDMRelatorioFactory.CreateCOMObject(nil) as IRDMRelatorio;
Result.RDM := Self;
Result.SQLConnection := Integer(SQLConnection1);
end;

O que esse RDMRelatorioFactory que vc colocou ?....não seria somente RDMRelatorio ?....não entendi essa parte.

function TRDMRelatorio.Get_RDM: IRDM;
begin
Result := FRDM;
end;

procedure TRDMRelatorio.Set_RDM(const Value: IRDM);
begin
FRDM := Value;
end;

function TRDMRelatorio.Get_SQLConnection: Integer;
begin
Result := Integer(FRDM.SQLConnection);
end;


e nessas...o que seria FRDM ?...tb n]ao entendi.....e mais uma coisa...isso tb funciona qdo se usa Transaction Data Modules ?

vlww pela atenção meu caro!!!..obrigado!

Marcelo


GOSTEI 0
Kotho

Kotho

17/05/2005

Vamos ver se consigo exclarecer todas as dúvidas, ok?
---

Quando se cria um novo RemoteDataModule ou TransactionDataModule, ele utiliza este trecho no inicialization do DataModule...

initialization
  TComponentFactory.Create(ComServer, TRDM,
    Class_RDM, ciMultiInstance, tmApartment);
end.


Por isso é preciso usar o mesmo método para instanciar os DataModules no DataModule principal...

Foi bom você ter tido essas dúvidas, porque tem que se mudar mais algumas coisas (eu tinha dito que era chatinho), e que eu tinha esquecido...

ele também define a variavel RDMRelatorio: TRDMRelatorio;

é preciso mudar para RDMRelatorioFactory: TComponentFactory;

e no inicialization

  RDMRelatorioFactory := TComponentFactory.Create(ComServer, TRDMRelatorio,
    Class_RDMRelatorio, ciInternal, tmApartment);


Isso, eu creio, que sirva para que o DataModule não seja criado sozinho, mas que o DataModule Principal o crie...
---

As procedures Get´s e Set´s são, automaticamente, usadas pelo SharedConnection (que fica no Client), para fazer a instância dos DataModules.
---

Cada DataModule deve ter uma variável (privada) declarada... no meu caso eu fiz...

FRDM: IRDM

onde RDM é o meu DataModule principal. IRDM é a interface (no arquivo TLB)...
---

Bom... quando se usa essa forma, quando um client se conecta ao server, ele cria uma nova Thread, com a cópia do DataModule Principal e dos demais... com isso, a propriedade SQLConnection pode ser perdida... por isso tem que se usar os GetSQLConnection, para atribui-lo aos componentes... para fazer isso, é preciso serializar o componente, por isso o Integer(FRDM.SQLConnection).
---

Para ser bem simplista, no DataModule Principal são instanciados os DataModules secundários... e nos secundários, é referenciada (através de interface) o Principal, assim como o SQLConneciton.

Isto, porque, não se consegue referenciar um DataModule no outro de forma direta (declarando na uses)... é preciso passar a referencia do objeto de um para o outro.

E tudo isso, quem ajuda, é o SharedConnection no Client...
---

Eu sei que pode parecer confuso... mas eu vou tentar ajudar, da forma que eu puder...


GOSTEI 0
Tchelllo

Tchelllo

17/05/2005

Então Kotho...veja o que estou fazendo de errado, pois não consegui ainda...

nessa function...

function TRDM.Get_RDMRelatorio: IRDMRelatorio;
begin
Result := RDMRelatorioFactory.CreateCOMObject(nil) as IRDMRelatorio;
Result.RDM := Self;
Result.SQLConnection := Integer(SQLConnection1);
end;

como faço para obter esse valor....Result.RDM := Self; e
Result.SQLConnection := Integer(SQLConnection1); ????.....pois aqui só me aparece os métodos de IRDMRelatorio quando digito Result.

e nessa..

function TRDMRelatorio.Get_SQLConnection: Integer;
begin
Result := Integer(FRDM.SQLConnection);
end;

declarei na área private a variável como vc explicou...

FRDM : IRDM;

mas tb só me aparecem os métodos e não a propriedade SQLConnection....

O que estou fazendo de errado ?


GOSTEI 0
Kotho

Kotho

17/05/2005

Esse SQLConnection é uma property criada lá no TLB... no tópico que eu passei eu descrevi como está a estrutura do meu TLB... como está a sua???


GOSTEI 0
Tchelllo

Tchelllo

17/05/2005

//**********************************************************//
// The Class CoServerVendas provides a Create and CreateRemote method to
// create instances of the default interface IServerVendas exposed by
// the CoClass ServerVendas. The functions are intended to be used by
// clients wishing to automate the CoClass objects exposed by the
// server of this typelibrary. ************************************************************//
CoServer = class
class function Create: IServer;
class function CreateRemote(const MachineName: string): IServer;
end;

aqui no meu _TLB não tem nada a ver com o que vc passou....peguei essa parte...mas não sei se é esta que vc ker...o restante abaixo dessas linhas estão as class functios etc...


GOSTEI 0
Kotho

Kotho

17/05/2005

Não...não... após abrir o TLB, clique em F12. Irá abrir uma tela gráfica com a estrutura do TLB... não mexa no código...


GOSTEI 0
Tchelllo

Tchelllo

17/05/2005

typelib Server
[ uuid ´{E202BF71-1734-4220-87D4-C96ABF49DDA5}´,
version 1.0,
helpstring ´ServerSis Library´ ];

uses midas.dll, stdole2.tlb, stdvcl40.dll, stdvcl40.dll;

IServer = interface(IAppServer)
[ uuid ´{D3EF78A2-8A5B-4388-AE45-35F95A9FBFED}´,
version 1.0,
helpstring ´Dispatch interface for Server Object´,
dual,
oleautomation ]
function Get_SQLConn: Integer [dispid $0000012D]; safecall;
function Get_tdmCliente: ItdmClientes [dispid $0000012E]; safecall;
end;

Server = coclass(IServer [default] )
[ uuid ´{3834B633-6E50-40CA-983E-417D819B7CAF}´,
version 1.0,
helpstring ´Server Object´,
custom ´{17093CC8-9BD2-11CF-AA4F-304BF89C0001}´ 0 ];


peguei isso da aba Text da tela gráfica que se abriu....é isso?


GOSTEI 0
Kotho

Kotho

17/05/2005

no lado esquerdo da tela gráfica tem um TreeView... essa é a estrutura... ela é formada de CoClass, Interfaces, Propertys (read e/ou write) e Mathods...


GOSTEI 0
Tchelllo

Tchelllo

17/05/2005

A estrutura está assim: (vou descrevê-la como se fosse o proprio TreeView pra vc ver)

-ServerSis
-IServer
Get_SQLConnetion (method)
+Server
-ItdmClientes --> Este é outro Transaction Data Module
... outros methods
+tdmClientes

espero ter sido claro.


GOSTEI 0
Kotho

Kotho

17/05/2005

Blz... agora começamos a falar a mesma lingua...

no seu IServer, você tem que criar algumas propriedades...

SQLConnection - do tipo long - read
tdmClientes - do tipo ItdmClientes - read

no seu ItdmClientes...

SQLConnection - do tipo long - read/write
Server - do tipo IServer - read/write

--

Se você quizer facilitar o trabalho para não ter que criar as propriedades nos DataModules secundários, você pode criar uma interface base... eu chamei a minha de IBaseRDM... ai você cria as propriedades nessa interface... depois, na sua ItdmClientes, você muda a propriedade (do lado direito) Parent Interface para essa Interface Base, e não precisa criar as mesmas propriedades... Só precisará implementar as procedures/functions nos DataModules
--

detalhe... sempre que você alterar o TLB, e clicar no botão de refresh, as procedures/functions serão criadas nos DataModules, só faltando implementar...
---

aproveitando o post... como está a seção inicialization (fica no final da unit) dos seus DataModules???


GOSTEI 0
Tchelllo

Tchelllo

17/05/2005

Está assim:

initialization
TComponentFactory.Create(ComServer, TServer,
Class_Server, ciMultiInstance, tmApartment);

para o TDM Server, e...

initialization
tdmClientes := TComponentFactory.Create(ComServer, TtdmClientes,
Class_tdmClientes, ciMultiInstance, tmApartment);

para o outro...o TDMClientes

testei e deu certo agora....só que na aplicação cliente estou usando Socket...e quando coloco um SharedConnection a prop. ChildName fica em branco, não me retorna nada.....pq será que está acontecendo isso?....antes estava dando erro de Classe inválida....e agora isso...não aparece nada.


GOSTEI 0
Kotho

Kotho

17/05/2005

Você implementou as procedure/functions?

no DataModule principal (Server):
--GetSQLConnection
--GetTdmCliente

e no secundário (tdmCliente):
--GetSQLConnection
--SetSQLConnection
--GetServer
--SetServer


GOSTEI 0
Tchelllo

Tchelllo

17/05/2005

Quando se cria as propertys, automaticamente são criadas as function/procedures certo?...

no meu ficou assim:

No Server:

function TServer.Get_SQLConnection: Integer;
begin
// o Integer serve para serializar o componente
Result := Integer(sqlConnEmp); // nome do meu SQLConnection
end;


function TServer.Get_ItdmClientes: ItdmClientes;
begin
Result := tdmClientes.CreateCOMObject(nil) as ItdmClientes;
Result.Server := Self;
Result.SQLConnection := Integer(sqlConnEmp);
end;


e no tdmClientes:

function TtdmClientes.Get_Server: IServer;
begin
Result := FServer;
end;


procedure TtdmClientes.Set_Server(const Value: IServer);
begin
FServer := Value;
end;


function TtdmClientes.Get_SQLConnection: Integer;
begin
Result := Integer(FServer.SQLConnection);
end;

procedure TtdmClientes.Set_SQLConnection(Value: Integer);
var
x: integer;
begin
for x:=0 to ComponentCount -1 do
if Components[x] is TCustomSQLDataSet then
TSQLDataSet(Components[x]).SQLConnection := TSQLConnection(Value);
end;

Como vc me explicou, criei um Interface base com os Get´s e Set´s acima (não todos, apenas as 4 acima)...e depois alterei o Parent Interface de ItdmClientes para a base criada.

está algo errado ?


GOSTEI 0
Kotho

Kotho

17/05/2005

Tem uma coisinha que eu estou percebendo... no TLB, na Interface do Server, você criou a propriedade ItdmClientes do tipo ItdmClientes... na verdade, o nome da propriedade (no meu entender) deve ter o mesmo nome do DataModule...

ficaria tdmClientes do tipo ItdmClientes

Modifique isso, e avisa se deu certo


GOSTEI 0
Tchelllo

Tchelllo

17/05/2005

Ainda está em branco....estou fazendo testes com uma máquina remota...nela configurei na COM+ a DLL gerada no Delphi...está da seguinte forma:

-TESTE // nome da aplicação no catálogo
-Componentes
+ServerSis.Server
+ServerSis.tdmClientes

não está nada errado nao é?


GOSTEI 0
Kotho

Kotho

17/05/2005

Eu estava olhando melhor as suas configurações e comparando com as minhas... no tdmClientes, a Inicialization sua está ciMultInstance, e o meu está ciInternal... Só o principal deve estar ciMultInstance...

Cara, eu não entendi uma coisa... você está fazendo o Servidor como COM+ certo??? e o Cliente como Socket??? Por que???

Tenta colocar um DComConnection... no ServerName, selecione o Server... Coloque um SharedConnection... atribua o DComConnection no ParentConnection... ai é para aparecer o tdmClientes na lista do ChildName... Seleciona e pronto...

Acho que estas alterações serão suficientes para resolver... mas qualquer problemas, já sabe... estamos aqui...


GOSTEI 0
Tchelllo

Tchelllo

17/05/2005

Particularmente prefiro usar o SocketConnection...é igual o DCOMConnection só muda algumas propriedades como o Host, que não tem no DCom...

e sobre o SharedConnection, ainda está em branco :/....já tinha feito as alterações para ciInternal e nada.....

mas me deixe perguntar uma coisa....as functios/procedures não precisam ser executadas?...ou só precisam estar inseridas e implementadas?...não preciso tipo, colocá-las no onCreate do TDM e executá-las certo?


GOSTEI 0
Kotho

Kotho

17/05/2005

Não precisa não... o SharedConnection vai executa-los...

Eu tentei fazer uma conexão usando Socket, mas não está funcionando não... está me retornando um exception dizendo que a máquina de destino recusou...

eu fiz assim... coloquei o nome da máquina que o server está instalado no Host, depois tentei selecionar o ServerName... aí dá o erro...

Tchello, eu volto a insistir, usa o DComConnection... pelo menos faz um teste... o campo Host do Socket é similar ao ComputerName do DCom...

Coloque o nome da máquina (ou ip) no ComputerName, depois selecione o ServerName... é bem simples...


GOSTEI 0
Tchelllo

Tchelllo

17/05/2005

Então Kotho, já fiz o teste com o DCom, mas tb fica em branco a propriedade....não sei oq pode ser...:/

tem uma coisa que tá estranho....nessa passagem...

function TtdmClientes.Get_SQLConnection: Integer;
begin
Result := Integer(FServer.SQLConnection);
end;

quando compilo não dá erro nenhum....mas....quando digito FServer (que é a variável privada) e digito .(ponto)....não aparece a property SQLConnection...o que aparece de property é só a tdmClientes....deveria aparecer não é?


GOSTEI 0
Kotho

Kotho

17/05/2005

Não aparece mesmo...

Uma pergunta... quando você mudou o nome da propriedade de ItdmClientes para tdmClientes... você clicou no refresh... quando se faz isso, ele cria novas functions/procedures... dá uma olhada nisso...

talvez ele não tenha apagado as antigas... você deve passar o código para as novas functions/procedures...

Espero o retorno


GOSTEI 0
Tchelllo

Tchelllo

17/05/2005

Quando eu alterei o nome, as funções tb foram alteradas, mas não criadas novamente. O delphi apenas mudou o nome de Get_ItdmClientes para Get_tdmClientes.

Ah, quando vc tentou usar o SocketConnection, deu akele erro pois ele precisa de um .exe rodando na maquina hospedeira da aplicação...o exe chama-se scktsrvr.exe....fica nos diretorios do Delphi....

será que eu preciso apagá-las e criá-las de novo?...só por causa do nome...creio que não né...pois o delphi alterou pra mim....

e tb como está o relacionamento dos seus Tdm´s ?....vc colocou eles na cláusula uses?.....como está o seu ?


GOSTEI 0
Tchelllo

Tchelllo

17/05/2005

Sobe

A propósito Kotho, testei com RemoteDataModules. Como ele gera um .exe, tentei acessá-lo através de um Client e ele abriu a aplicação servidora....não é normal isso nao é?......nunca trabalhei com RemoteDataModules...por isso as dúvidas....kra...to ficando com os nervos a flor da pele....não consigo resolver esse problema!!...:/


GOSTEI 0
Kotho

Kotho

17/05/2005

A uses, eu só defini no RDM (principal) os Secundários...

Cara, era para estar tudo funcionando (fiz o teste com socket e funcionou)... muito estranho... vou colocar os trechos de código para a gente comparar ok?

RDM (DataModulePrincipal)
...
    function Get_SQLConnection: Integer; safecall;
    function Get_RDMConsulta: IRDMConsulta; safecall;
...
function TRDM.Get_SQLConnection: Integer;
begin
  Result := Integer(Amplast);
end;

function TRDM.Get_RDMConsulta: IRDMConsulta;
begin
  Result := RDMConsultaFactory.CreateCOMObject(nil) as IRDMConsulta;
  Result.RDM := Self;
  Result.SQLConnection := Integer(Amplast);
  Result.ADOConnection := Integer(ZIM);
end;
...
initialization
  TComponentFactory.Create(ComServer, TRDM, Class_RDM, ciMultiInstance, tmBoth);


RDMConsulta (Secundário)
...
    function Get_RDM: IRDM; safecall;
    procedure Set_RDM(const Value: IRDM); safecall;
    function Get_SQLConnection: Integer; safecall;
    procedure Set_SQLConnection(Value: Integer); safecall;
...
function TRDMConsulta.Get_RDM: IRDM;
begin
  Result := FRDM;
end;

procedure TRDMConsulta.Set_RDM(const Value: IRDM);
begin
  FRDM := Value;
end;

function TRDMConsulta.Get_SQLConnection: Integer;
begin
  Result := Integer(FRDM.SQLConnection);
end;

procedure TRDMConsulta.Set_SQLConnection(Value: Integer);
var
  x: Integer;
begin
  for x := 0 to ComponentCount -1 do
    if Components[x] is TCustomSQLDataSet then
      TCustomSQLDataSet(Components[x]).SQLConnection := TSQLConnection(Value);
end;
...
initialization
  RDMConsultaFactory := TComponentFactory.Create(ComServer, TRDMConsulta,
    Class_RDMConsulta, ciInternal, tmApartment);



GOSTEI 0
Tchelllo

Tchelllo

17/05/2005

Kotho, estou usando TransacationDataModules....e como vc está usando RemoteDataModules...será que não é por isso que não estou conseguindo ?...ou vc já testou com TDM´s e funcionou ?


GOSTEI 0
Kotho

Kotho

17/05/2005

Apesar do RDM... eu tbem utilizo Transactional... é que eu converti depois...

Os trechos estão iguais (trocando os nomes, é claro)???

Dá uma olhada na sua MP


GOSTEI 0
Tchelllo

Tchelllo

17/05/2005

Boas é más notícias Kotho...

Boa: Consegui fazer aparecer o bendito tdmClientes!!....aeeeeee

Ruim: Quando vou setar a propriedade ProviderName do meu ClientDataSet na aplicação Cliente com o DataSetProvider da aplicação servidora, dá o seguinte erro:

Catastrophic failure

já aconteceu isso com vc?


GOSTEI 0
Kotho

Kotho

17/05/2005

Cara... fala ae o que tava errado...

Você ainda não desistiu de usar Sockets??? hehe... brincadeira...

Esse erro já aconteceu comigo sim... É um erro que dá na aplicação servidora, só que o Server não consegue repassar para o Client...

Um detalhe muito importante em aplicações n-tier, é sempre verificar se não ficou algum componente conectado... isso pode causar erro...

Se não for nada disso, você terá que debugar o servidor

olha esse post [url]http://forum.clubedelphi.net/viewtopic.php?t=62922[/url], só que no seu caso, você terá que abrir o Delphi 2 vezes, conectar com o Server (manualmente), dai começar a debugar (o server), depois tentar selecionar o DataSetProvider...


GOSTEI 0
Tchelllo

Tchelllo

17/05/2005

Kotho, descobri o porque do erro...

estava seguindo o demo SharedConnection do delphi, e no RDM principal ele usa um TSession, (não sei se vc chegou a abrir esse demo)...e na propriedade Session da IBaseRDM, ele define o tipo como WideString para pegar o nome do componente. E eu, no embalo, também programei para pegar o nome do SQLConnection e não o Integer como vc tinha me dito, daí o erro ´Catastrophic failure´ no momento da conexão.

E sobre a prop. ChildName, não sei o porque que deu certo agora...pois o q fiz foi refazer o servidor do zero, criei os TDM´s (principal e secundários)...criei e implementei suas propriedades, depois inseri no catálogo COM+ a dll, conectei o client e quando cliquei sobre a prop. ChildName, lá estava o tdmClientes!!.

Bom...felizmente consegui resolver, e espero que outras pessoas com as mesmas dúvidas consigam também, e concerteza esse tópico irá ajudar bastante!.

Muito obrigado pela super atenção e ajuda Kotho. valeu mesmo!!!

Abraços


GOSTEI 0
Seu_madruga

Seu_madruga

17/05/2005

Pessoal, aproveitando o tópico de vcs, que é muito interessante por sinal, porém não entendi quase nada. A idéia que eu quero é mais ou menos a de vcs, não sei ao certo.

Bom, na minha aplicação Servidora, tenho um RemoteDataModule e tbém um DataModule, pois no Servidor de Aplicação preciso acessar o banco de dados para poder cadastrar alguns registros. Bom, não sei o porque mas o RemoteDataModule não é enxergado no servidor, acho que porque ele sendo um RemotoDataModule, só é enxergado remotamente certo? E tbém o RemoteDAtaModule não se comunica com o DetaModule tbém. O que eu queria é, já que o RemoteDataModule não é enxergado na aplciação servidora, coloquei um DataModule nele, e como o SQLConnection está no RemoteDataModule, para conectar ao BD no DataModule, precisei colocar outro SQLconection identico no nele. A Pergunta é:

Realmente o remoteDataModule é incomunicável na aplicação local? Ele só pode ser acesado remotamente?


GOSTEI 0
Tchelllo

Tchelllo

17/05/2005

Seu_madruga, faça o seguinte:

Coloque o SQLConnection no DataModule comum do seu servidor e não no RemoteDataModule.

No Create do seu RemoteDataModule, crie o DataModule comum e faça um loop aos seus SQLDataSets do RemoteDataModule, conforme o código abaixo:

procedure TSeuRemoteDataModule.RemoteDataModuleCreate(Sender: TObject);
var i: word;
begin
  if DataModule = nil then
    DataModule := TDataModule.Create(DataModule);

  for i := 0 to ComponentCount - 1 do
    if Components[i] is TSQLDataSet then
      if (Components[i] as TSQLDataSet).Tag = 0 then
        (Components[i] as TSQLDataSet).SQLConnection := DataModule.SQLConnection;

end;


Isso faz com que seus SQLDataSets usem o SQLConnection do DataModule comum.

Esse código no create do RemoteDataModule não é necessário, mas é bom implementá-lo pois já tive problemas da propriedade SQLConnection ser perdida nos SQLDataSets no momento da execução da aplicação.

Também há outras formas de acessar o RemoteDataModule através de TSharedConnection, mas fazendo dessa forma acima, funciona.


GOSTEI 0
POSTAR