Mapeamento Híbrido
O recurso de Mapeamento Híbrido é o "super poder" do BridgeFrameWork para lidar com sistemas legados. Ele permite que você use SQL customizado para performance ou complexidade, mas ainda trabalhe com objetos tipados na sua aplicação.
O Problema
Muitas vezes, uma query de relatório, um dashboard ou até mesmo um Grid complexo precisa de 5 JOINs, GROUP BY e sub-selects. Tentar escrever isso com métodos de ORM (Find, Where) é doloroso e ineficiente.
A Solução: SQL no Model, Objetos no Controller
1. No Model
Crie um método no seu Model específico que retorna um TFDMemTable. Aqui você tem liberdade total para escrever o SQL que precisar.
function TPedidoModel.ObterPedidosAtrasados(ADias: Integer): TFDMemTable;
const
CSQL = 'SELECT p.* ' +
'FROM PEDIDO p ' +
'JOIN CLIENTE c ON c.ID = p.ID_CLIENTE ' +
'WHERE p.STATUS = ''A'' ' +
'AND p.DATA < %s';
begin
// Executa o SQL formatado e retorna um TFDMemTable
Result := Self.FindCustom(Format(CSQL, [
QuotedStr(FormatDateTime('yyyy-mm-dd', Now - ADias))
]));
end;
2. No Controller (Intermediário)
Implemente um método no Controller que encapsule o acesso ao Model. Isso mantém o isolamento das camadas.
type
TPedidoController = class(TBaseController<TPedido>)
public
function BuscarPendencias(ADias: Integer): TFDMemTable;
end;
function TPedidoController.BuscarPendencias(ADias: Integer): TFDMemTable;
begin
// Cast seguro pois sabemos que o Model de TPedidoController é um TPedidoModel
Result := (Model as TPedidoModel).ObterPedidosAtrasados(ADias);
end;
3. Na View (Consumindo)
Na sua tela ou rotina, trabalhe com o Controller específico (tipado).
procedure TRelatorioController.ProcessarAtrasados;
var
LLista: TObjectList<TPedido>;
LDataSet: TFDMemTable;
LController: TPedidoController; // Tipo específico
begin
LLista := TObjectList<TPedido>.Create;
// Obtém a instância já com o tipo correto (pode exigir cast se o Registry retornar IController)
LController := TControllerRegistry.Instance.Get<TPedido> as TPedidoController;
try
// 1. Obtém o DataSet através do método do Controller
LDataSet := LController.BuscarPendencias(30);
// 2. Mapeia para Objetos
// Como LController é TPedidoController (que herda de TBaseController),
// temos acesso direto ao LoadFromDataSet sem casts adicionais.
LController.LoadFromDataSet(LLista, LDataSet);
// 3. Itera sobre objetos fortemente tipados
for var LPedido in LLista do
begin
if LPedido.Valor > 1000 then
NotificarGerente(LPedido);
end;
finally
LController.Free; // Se não for gerenciado pelo Registry/Interface
LLista.Free;
LDataSet.Free;
end;
end;
Regras de Ouro
- Colunas: O seu SQL deve retornar colunas com os mesmos nomes definidos nos atributos
[Column]da sua entidade. Colunas extras no SQL são ignoradas. Colunas faltantes no SQL ficarão com valor default no objeto. - Performance: O mapeamento é feito em memória e é muito rápido. O gargalo será a execução do seu SQL no banco.