Pular para o conteúdo

A Jornada Dext: Evoluindo a Alta Performance no Backend Delphi

Dext v1 RC

O desenvolvimento de sistemas enterprise exige evolução constante. No Project Dext, nosso objetivo nunca foi apenas entregar um produto finalizado, mas sim construir uma base sólida, moderna e performática para a comunidade Delphi. Hoje compartilhamos mais uma evolução fundamental: o estágio Release Candidate 1.0.

Esta atualização consolida meses de refinamento no motor do framework, trazendo recursos que antes pareciam distantes do ecossistema Object Pascal.


✨ Features Principais: A Evolução Final antes da v1.0

Seção intitulada “✨ Features Principais: A Evolução Final antes da v1.0”

Simplificamos drasticamente a exposição de dados e a execução de consultas complexas, trazendo o ORM para um nível de expressividade sem precedentes.

A funcionalidade de gerar endpoints automáticos (“Database as API”) recebeu um upgrade significativo na sua integração. Agora, com o MapDataApi, você registra um CRUD completo e seguro diretamente no builder da aplicação, com suporte nativo a injeção de dependência e políticas de acesso.

// Uma única linha para expor sua entidade com segurança
App.Builder.MapDataApi<TProduct>('/api/v1/products',
DataApiOptions.RequireAuth.AllowReadWrite
);

Database as API

🔍 Dynamic Specification Mapping: O seu Cliente no Controle

Seção intitulada “🔍 Dynamic Specification Mapping: O seu Cliente no Controle”

Integrada nativamente ao Database as API, a filtragem via QueryString permite que o cliente da sua API construa consultas complexas sem que você escreva uma linha de lógica no backend. O Dext mapeia sufixos inteligentes diretamente para o SQL.

Exemplos de URLs poderosas:

  • GET /api/v1/products?price_gt=100&stock_lt=10 -> Filtra preço > 100 e estoque < 10.
  • GET /api/v1/products?name_cont=Dext&_sort=id desc -> Busca nomes que contenham “Dext” com ordenação decrescente.
  • GET /api/v1/products?category_in=1,2,5 -> Filtra por múltiplos valores simultâneos.

Isso transforma sua API em uma ferramenta flexível, reduzindo a necessidade de criar múltiplos métodos de busca para cada combinação de filtros.

🔗 Multi-Mapping ([Nested]): O “Dapper” do Delphi

Seção intitulada “🔗 Multi-Mapping ([Nested]): O “Dapper” do Delphi”

Implementamos um suporte nativo a Multi-Mapping inspirado no Dapper. Usando o atributo [Nested], o Dext consegue hidratar grafos de objetos complexos a partir de uma única query SQL com joins.

Imagine carregar um TOrder que possui um TCustomer e este possui um TAddress. No Dext, isso é feito de forma recursiva e performática, mapeando a hierarquia de classes em uma única ida ao banco.

var OrderProxy := Prototype.Entity<TOrder>;
var Orders := Db.Orders
.Include(OrderProxy.Customer) // Carregamento antecipado via Proxy
.ThenInclude(OrderProxy.Customer.Address)
.ToList;

Multi-Mapping

🔒 Pessimistic Locking: Controle Total de Concorrência

Seção intitulada “🔒 Pessimistic Locking: Controle Total de Concorrência”

O controle de concorrência agora é nativo na API fluente. Você pode solicitar locks no nível do banco de dados para transações críticas diretamente na consulta:

var Product := Db.Products
.Where(Prop('Id') = 1)
.Lock(TLockMode.Update) // Gera FOR UPDATE (PostgreSQL) ou UPDLOCK (SQL Server)
.FirstOrDefault;

🛠️ Stored Procedures & Views: Cidadãos de Primeira Classe

Seção intitulada “🛠️ Stored Procedures & Views: Cidadãos de Primeira Classe”

Sabemos que o mundo real exige o uso de lógicas complexas que residem no banco de dados. O Dext simplificou drasticamente a interação com Stored Procedures e Views.

  • Views: Mapeie Views complexas exatamente como tabelas, aproveitando todo o poder da hidratação automática.
  • Stored Procedures: Mapeamento declarativo usando atributos, com suporte a parâmetros de entrada, saída e variados tipos de retorno.
type
[StoredProcedure('GetEmployeeSalary')]
TEmployeeSalaryDTO = class
private
FEmpId: Integer;
FSalary: Double;
FBonus: Double;
public
[DbParam(ptInput)]
property EmpId: Integer read FEmpId write FEmpId;
[DbParam(ptOutput)]
property Salary: Double read FSalary write FSalary;
[DbParam(ptOutput, 'p_bonus')]
property Bonus: Double read FBonus write FBonus;
end;

Isso garante que você possa utilizar recursos avançados de bancos como SQL Server e PostgreSQL sem sacrificar a tipagem forte e a elegância do seu código Pascal.


A refatoração do motor de Interception (Proxying) para o Core trouxe algo revolucionário: a capacidade de gerenciar estados sem poluir os campos (fields) da sua classe. É o que chamamos de Shadow Fields e Anonymous States.

Isso permite que você tenha dados persistidos no banco (como TenantId, AuditLog, ou Chaves Estrangeiras) que seu código de domínio sequer enxerga. A classe permanece um POCO (Plain Old CLR Object) puro, enquanto o ORM gerencia os metadados “nas sombras”.

Exemplo Prático: Isolamento de Tenant sem poluir o Domínio Sua classe de domínio não precisa saber que o Banco de Dados exige um TenantId em cada linha:

[Table('Products')]
TProduct = class
public
[PK, AutoInc] property Id: Integer ...
property Name: string ...
// Repare: NÃO existe campo TenantId aqui!
end;

Mapeamento Fluente (Shadow Property):

ModelBuilder.Entity<TProduct>
.ShadowProperty('TenantId') // Propriedade fantasma!
.HasColumnName('tenant_id');

O que o Dext faz no Banco:

SELECT Id, Name, tenant_id FROM Products WHERE tenant_id = :current_tenant

Como acessar o Shadow Field se precisar? Você pode ler ou escrever esses valores via API de Entry:

var TenantId := Db.Entry(Product).Member('TenantId').GetCurrentValue.AsInteger;

Isso traz para o Delphi uma funcionalidade similar aos Objetos Anônimos ou Propriedades Dinâmicas de frameworks modernos, permitindo arquiteturas limpas onde o Banco de Dados não dita o design das suas classes.


O framework web agora utiliza o TUtf8JsonWriter para o motor de Database as API.

  • Os dados são escritos em streaming direto do banco de dados para o socket.
  • Zero-Allocation: Quase não há alocações temporárias de strings, o que reduz drasticamente a pressão no Garbage Collector (ou a fragmentação do Heap no Delphi) e aumenta o throughput massivamente.

Para demonstrar o poder do Dext em cenários do mundo real, criamos uma nova série de exemplos focados em Domain-Driven Design (DDD) simplificado e Testes Unitários. Estes projetos mostram como o Dext se integra perfeitamente em arquiteturas limpas e desacopladas.

Os novos exemplos exploram a separação de responsabilidades, usando o Dext para gerenciar a persistência sem que ele dite as regras de negócio:

  • Web.SalesSystem & Web.FoodDelivery: Demonstram o uso de Services, Repositories e Domain Entities com validações ricas integradas ao ciclo de vida do ORM.
  • Web.TicketSales: Focado em alta concorrência e o uso de Pessimistic Locking para garantir a integridade na venda de ingressos.
  • Web.HelpDesk: Um sistema completo de chamados que utiliza o motor de Database as API para agilizar o frontend, mantendo lógicas customizadas onde necessário.

Todos esses exemplos vêm acompanhados de suites de Testes Unitários e de Integração. Mostramos como o Dext facilita o “Mocking” e a criação de ambientes isolados para testes, garantindo que sua lógica de banco seja testável e confiável.

  • MultiTenancy: Demonstração técnica de isolamento via Schema (PostgreSQL) e via Banco de Dados com troca dinâmica de conexões.
  • SmartPropsDemo: O uso avançado de Prop<T> e Nullable<T> para persistência transparente e controle total de mudanças (Dirty Tracking).
  • SQL Generator: Melhoria na geração de DDL, ignorando navigation properties no CREATE TABLE.
  • TActivator: Priorização inteligente de construtores de classes derivadas.
  • Lazy Loading: Correção de Access Violations em proxies de relacionamentos circulares.

O trabalho não para. Já iniciamos um refactor profundo no Dext.Collections. Nosso objetivo é eliminar completamente a dependência do generics padrão do Delphi, atacando o “code bloat” (inchaço do .exe) e elevando a performance a um novo patamar de excelência.

Dext Collections Mystery

A evolução é constante. O Dext está apenas começando.