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