Olá a todos! Me chamo Leonardo Quartieri sou programador Delphi e trabalho com desenvolvimento de sistemas, na grande maioria Orientado a Objetos :) , certo dia desenvolvendo uma classe de persistência, a qual o objetivo era ser o mais completa e abranjente possível, me deparei com um problema, qual tipo de retorno eu deveria extrair da minha função de select??? um Dataset ou um Datareader? Compreendendo as caracteristicas de cada um percebi que a melhor solução seria que a função pudesse me retornar os dois, mas como? A solução foi a seguinte,

Criar um Tipo, observe como é simples o codigo da unit do tipo:

############################

unit DsetouDReader;

// Esta unit deve ser declarada em toda unit que usar o retorno TDsetouDReader

interface


uses

System.Data, System.Data.SqlClient;


type

TDSetouDReader = record

DSet : Dataset;

DReader : SQLDataReader;


end;

implementation


end.

############################


Após a criação do tipo, na classe de persistência implementei o select da seguinte forma:


############################ (camada persistencia)

function TPersistenciaGeral.Select(ValueObject: TObject; SetouReader: integer; Order: String):TDSetouDReader;

// Este select pode ser tanto um select * como um select com where, depende das properties

//SetouReader = 0 = Dataset

//SetouReader = 1 = Datareader;

Var

vTabela: &Type;

vSQLCommand : SQLCommand;

vSQLDataAdapter : SQLDataAdapter;

vPropriedades: Array of PropertyInfo;

vPropriedade: PropertyInfo;

vDataset : Dataset;

StringcomPercent: string;

Dr: SqlDataReader;


begin

vSQLDataAdapter := SQLDataAdapter.Create;

vSQLCommand := SQLCommand.Create;

vDataset := Dataset.Create;

vTabela := ValueObject.GetType;

vPropriedades := vTabela.GetProperties;

if vSQLConnection.State = ConnectionState(0) then

vSQLConnection.Open;

vSQLCommand.Connection := vSQLConnection;


vTabela := ValueObject.GetType;

vSQLCommand.CommandText := 'Select * from '+vTabela.Name.Substring(1)+ ' where 1 = 1 ';


for vPropriedade in vPropriedades do // se houver alguma property com valor faz-se where

begin

if (vPropriedade.GetValue(ValueObject,nil) <> nil)then

begin

try

begin

if ((Convert.Toint32(vPropriedade.GetValue(ValueObject,nil)) <> 0)) then

begin

vSQLCommand.CommandText := vSQLCommand.CommandText +' And '+vTabela.Name.Substring(1)+'.'+vPropriedade.Name+' = '+

quotedstr(Convert.tostring(vPropriedade.GetValue(ValueObject,nil)));

end;

end;

except

begin

if ((Convert.tostring(vPropriedade.GetValue(ValueObject,nil)) <> '')) then

begin

StringcomPercent :='%'+convert.tostring(vPropriedade.GetValue(ValueObject,nil))+'%';

vSQLCommand.CommandText := vSQLCommand.CommandText +' And '+vPropriedade.Name+' Like '+QuotedStr(

StringcomPercent);

end;

end;

end;

end;

end;

if order <> '' then

vSQLCommand.CommandText := vSQLCommand.CommandText + ' Order by '+Order;


vSQLDataAdapter.SelectCommand := vSQLCommand;

if SetouReader = 0 then

begin

vSQLDataAdapter.Fill(vDataset);

Result.Dset := vDataset;

end;

if SetouReader = 1 then

begin

Dr :=vSQLCommand.ExecuteReader;

Result.DReader := Dr;

end;

end;

############################


Digerindo o codigo acima,

Com o ValueObject recebemos a classe a ser lida, por ser uma classe de persistencia geral a mesma captura a classe que a invocou, lê as properties da classe, as properties que não forem vazias ou nulas são colocadas no where na montagem do SQL, após isso passamos o parâmetro que define como vai ser o retorno, e para terminar passamos a ordenação dos dados. Como a aplicação é em camadas, observe abaixo o modelo utilizado:

Camada de Apresentação (Tela)

Camada de Fachada

Camada de Bussines

Camada de Persistência

BANCO DE DADOS 



Neste modelo todas as classes geram suas tabelas no banco de dados, se as tabelas não existirem claro, as properties são os campos da tabela, na tela instancio as classes Clientes e FachadaClientes, já chamando o método criado na fachada, observe:

############################ (Tela)

procedure TWebForm1.Page_Load(sender: System.Object; e: System.EventArgs);

var

Clientes : TClientes;

FaClientes : TFachadaClientes;

begin

Clientes := Tclientes.Create; // Esta classe só contem as properties

FaClientes := TFachadaclientes.Create;


DataGridDset.DataSource := FaClientes.SelecionarClientes(Clientes,0,'Nome').DSet;

DataGridDset.DataBind;


DataGridReader.DataSource := FaClientes.SelecionarClientes(Clientes,1,'Nome').DReader;

DataGridReader.DataBind;


end;

############################


Indo uma camada abaixo, observe a implementação do método na camada FachadaClientes:


############################ (Camada Fachada)
class function TFachadaClientes.SelecionarClientes(Clientes: TClientes; SetouReader: integer; Order: String): TDSetouDReader;

Var

vBusClientes : TBusClientes;

begin

vBusClientes := TBusClientes.create;

result := vBusClientes.SelecionarClientes(Clientes,SetouReader,order);

end;

############################


Indo uma camada a baixo observe:


############################ (Camada Bussines)
function
TBusClientes.SelecionarClientes(Clientes: TClientes; SetouReader: integer; Order: String): TDSetouDReader;

Var

vClientes : TpClientes; // Classe de pesrist especifica, herda o método de TPersistenciaGeral

begin

vClientes := TpClientes.Create;

result := vClientes.Select(Clientes,SetouReader,Order);

end;

############################


No codigo da pagina inicial(Tela) note que coloquei dois datagrids, um sendo alimentado por um dataset e outro sendo alimentado por um DataReader. A grande sacada nesta solução é realmente o uso de um tipo para possibilitar mais que um retorno na função, espero ter ajudado, qualquer dúvida, sugestão, ou melhora na solução entrem em contato : leoquartieri@hotmail.com



Agradecimentos super especiais a Eduardo Flaeschen (QD Tecnologia),
mais que um professor, um Mestre na arte de programar.



Leonardo Quartieri

leoquartieri@hotmail.com