quinta-feira, 25 de julho de 2019
segunda-feira, 27 de maio de 2019
domingo, 24 de junho de 2018
09:42
ORMBr & MongoDB
Finalmente anuncio que o ORMBr agora suporte o banco NoSQL MongoDB.
Depois de algumas tentativas e desistências, dessa vez foi, usando a engine FireDAC, o ORMBr foi ajustado para suportar bancos NoSQL, inicialmente MongoDB com FireDAC, quem sabe num futuro proximo outros bancos NoSQL e outros engines de acesso a dados.
Espero que gostem.
Depois de algumas tentativas e desistências, dessa vez foi, usando a engine FireDAC, o ORMBr foi ajustado para suportar bancos NoSQL, inicialmente MongoDB com FireDAC, quem sabe num futuro proximo outros bancos NoSQL e outros engines de acesso a dados.
Espero que gostem.
Grande abraço a todos
Isaque Pinheiro
Isaque Pinheiro
segunda-feira, 31 de julho de 2017
05:00
ORMBr - ORM Fácilita a Programação Orientada a Objetos?
Recebi uma pergunta esses dias pertinente a ajudar a quem só se houve falar na sigla ORM, e não sabe qual o real beneficio de se utilizar um ORM no seu dia dia.
A pergunta foi "O objetivo principal do ORMBr é fácilitar a programação Orientada a Objetos?"
Então resolvi deixar descrito aqui no meu blog a resposta, ficando assim publico para que todos que tenham essa dúvida possa pelo ao menos ficar mais informado sobre para que aderir um ORM em seus projetos.
Resposta: Na verdade eu considero que não, vou falar aqui o ORMBr e não dos ORMs no geral.
O ORMBr por exemplo te ajuda automatizando processos que você teria que escrever para gerenciamento de manipulação de dados manualmente.
Exemplos:
* Criar Tabelas, Fk, Pk, Indexe no banco, o ORMBr cria.
* Criar os TFields nos Datasets em designer, não precisa, pois o ORMBr cria automaticamente para você, então não precisa fazer isso manualmente.
* Parametrizar todos os TFields em Designer, não precisa, pois o ORMBr parametriza para você com base na classe modelo, não precisa fazer isso manual
* Escrever os comandos SQL para abrir os dados e fazer um CRUD em uma tabela, não precisa, pois o ORMBr monta o SQL para você e faz todo o CRUD com base na classe modelo.
* Linkar os componentes mestre-detalhe para o gerenciamento de abertura, fechamento etc, não precisa, pois o ORMBr faz isso automaticamente para você.
* Escrever comandos SQL, da quais muitas das vezes suja seu código, não precisa, o ORMBr tem a interface de classe ICriteria, que monta comando SQL usando POO.
* Te da possibilidade e facilidade do seu sistema ser multi-banco de dados.
Bom acho que está de bom tamanho, além de vários outros recursos.
Agora isso independente se irá desenvolver usando POO, pois com o ORMBr você pode trabalhar usando DataSet tendo todos os recursos que já se conhece hoje com os componentes dataware, ou optar por trabalhar buscando o máximo do POO, tratando e buscando dados direto por objeto do tipo e lista de objetos.
A pergunta foi "O objetivo principal do ORMBr é fácilitar a programação Orientada a Objetos?"
Então resolvi deixar descrito aqui no meu blog a resposta, ficando assim publico para que todos que tenham essa dúvida possa pelo ao menos ficar mais informado sobre para que aderir um ORM em seus projetos.
Resposta: Na verdade eu considero que não, vou falar aqui o ORMBr e não dos ORMs no geral.
O ORMBr por exemplo te ajuda automatizando processos que você teria que escrever para gerenciamento de manipulação de dados manualmente.
Exemplos:
* Criar Tabelas, Fk, Pk, Indexe no banco, o ORMBr cria.
* Criar os TFields nos Datasets em designer, não precisa, pois o ORMBr cria automaticamente para você, então não precisa fazer isso manualmente.
* Parametrizar todos os TFields em Designer, não precisa, pois o ORMBr parametriza para você com base na classe modelo, não precisa fazer isso manual
* Escrever os comandos SQL para abrir os dados e fazer um CRUD em uma tabela, não precisa, pois o ORMBr monta o SQL para você e faz todo o CRUD com base na classe modelo.
* Linkar os componentes mestre-detalhe para o gerenciamento de abertura, fechamento etc, não precisa, pois o ORMBr faz isso automaticamente para você.
* Escrever comandos SQL, da quais muitas das vezes suja seu código, não precisa, o ORMBr tem a interface de classe ICriteria, que monta comando SQL usando POO.
* Te da possibilidade e facilidade do seu sistema ser multi-banco de dados.
Agora isso independente se irá desenvolver usando POO, pois com o ORMBr você pode trabalhar usando DataSet tendo todos os recursos que já se conhece hoje com os componentes dataware, ou optar por trabalhar buscando o máximo do POO, tratando e buscando dados direto por objeto do tipo e lista de objetos.
04:42
ORMBr - Driver de Acessoa a Dados UniDAC
Dar tempo ao tempo é algo complicado quando estamos esperando ansiosamente alguma coisa, mas o que importa é vermos acontecer no dia a dia e dar um passo de cada vez.
O ORMBr deu mais um passo importante nesses dias, e um deles foi a doação do Marcos Nielsen ao projeto que foi o Driver de acesso a dados via UniDAC somando assim mais um Engine de acesso a dados a galeria, agora são eles:
Deixo aqui em nome do Projeto ORMBr o agradecimento a todos que estão colaborando, tanto usando, reportando situações, contribuindo, até mesmo só olhando, meu MUITO Obrigado.
- FireDAC
- DBExpress
- Zeos
- ADO
- AbsoluteDB
- SQLite Nativo
- UniDAC
Deixo aqui em nome do Projeto ORMBr o agradecimento a todos que estão colaborando, tanto usando, reportando situações, contribuindo, até mesmo só olhando, meu MUITO Obrigado.
sexta-feira, 5 de maio de 2017
05:02
DBCBr - Database Compare Brasil
O DBCBr, é um framework que tem como finalidade comparar e atualizar estrutura de banco de dados, como ele é um framework e ainda não uma ferramenta, seu código pode fazer parte da sua app.
DBCBr nasceu juntamente com o ORMBr, pois o mesmo o usa para fazer as atualizações do banco com base nos modelos, e como o ORMBr é uma tecnica ainda não tão bem difundica e usada, achei por bem, criar um novo projeto com esse recurso, o qual a pesar de muitos já fazerem pelo seus sistemas atualização de banco de dados, também muitos ainda não tem, e se tem pensam em melhora-lo.
O DBCBr, ainda não está maduro em recursos, mas está em estrutura, ou seja sua estrutura interna está pronto para atender qualquer necessidade, para comparar, identificar e gerar o script de atualização de qualquer banco de dados relacional.
Nós sabemos que atualizar banco de dados não é tão simples como parece, pois regras de integridade, as quais usamos e devemos usa-las, atrapalha no momento de executar o script de atualização, tendo que nos preocurar com vários detalhes e ordens, seja ele para criar algo novo, mudar algo que já exista ou até mesmo dropar algo existente, por essas razões o crescimento do DBCBr depende de testes e a ajuda de vocês, no que diz repeito a melhor forma de executarmos cada scripts de atualizações gerados.
O crescimento do DBCBr irá gerar o crescimento também do ORMBr, que o usa como complemento de recurso, agora quer uma ferramenta de Database Compare boa e de graça, estude o código do DBCBr, vamos discutir juntos, vamos unir conhecimentos e assim teremos o que precisamos, e com isso todos ganham, EU, Você e o ORMBr.
Estou a disposição para qualquer discussão sobre o assunto, novidades, dúvidas, discussões podem ser feito através do mesmo canal/grupo do ORMBr
Canal: https://t.me/canalormbr
Grupo: https://t.me/ormbr
domingo, 23 de abril de 2017
11:12
Mitos Sobre os TDataModules
Seja bem vindo, e ótima leitura.
Teve uma discussão sadia sobre o uso de datamodule no face postado por Savério Vertoni Jr. em cima da seguinte imagem:
Sou do signo de gêmios, dizem que quem é de gêmios quer convencer as pessoas da sua verdade ou do que acham que é verdade, eu particularmente gosto de usar fundamentos para mostrar o que acredito ser a minha verdade, claro temos livre arbítrio para escolhermos o que achamos que é melhor para nós, isso nós chamamos de liberdade de expressão. Teve uma discussão sadia sobre o uso de datamodule no face postado por Savério Vertoni Jr. em cima da seguinte imagem:
Agora podemos sim expor o que achamos certo e se quisermos que alguém acredite façamos da forma concreta, mostrando o porque da opinião, e talvez ai, alguém irá vê que sua opinião tem base para ser verdade ou não.
Nesse poste podemos ver alguns cenários para exemplificar o uso de datamodules é sobre o que visualizei que vou comentar.
Os comentários do post foi com base em uma pratica totalmente inviável como visto na imagem acima, vou explicar porque, também teve comentários que disseram que devemos criar um datamodule por módulo de sistema, também inviável, vou explicar porque, e comentário sobre o que disse o Vertoni em cria datamodule por form, "haja memória", isso é mito, pois uso de datamodulo por form não estoura memoria, na minha opinião á a melhor maneira de se usar datamodule, vou explicar porque.
Cenário 1 - Uma datamodule único com tudo nele, como mostrado no na imagem do post é inviável porque?
Cenário 1 - Uma datamodule único com tudo nele, como mostrado no na imagem do post é inviável porque?
a) Teremos que instância-lo no inicio da aplicação, isso irá sobrecarregar a abertura da app pela quantidade demaciada de componentes
b) Terá que ficar disponível enquanto a aplicação estiver aberta, pois todo mundo dependerá de usa-lo.
c) Manutenção no fonte desse datamodule, tente visualizar o fonte com os vários eventos de cada um componente ativo, impraticável implementar, corrigir, achar algo de forma escalável, pois terá rotina que atenderá a todo mundo.
Cenário 2 - Datamodule por módulo de sistema é inviável porque?
b) Terá que ficar disponível enquanto a aplicação estiver aberta, pois todo mundo dependerá de usa-lo.
c) Manutenção no fonte desse datamodule, tente visualizar o fonte com os vários eventos de cada um componente ativo, impraticável implementar, corrigir, achar algo de forma escalável, pois terá rotina que atenderá a todo mundo.
Cenário 2 - Datamodule por módulo de sistema é inviável porque?
a) Independente de como se organiza quais componentes colocar no datamodule de cada módulo, sempre terá nesse datamodule informações que não será usado por alguma situação, e nesse momento tenho informações na memória desnecessárias.
b) Terá que ficar disponível sempre, pois a qualquer momento, algum form que faz parte do módulo precise acessa-lo. Agora se criar um para cada form que precise dele, pior ainda, ai inchar a memória mesmo, cada um com um montão de coisa desnecessária.
c) Manutenção no fonte desse datamodule, tente visualizar o fonte com os vários eventos de cada um componente ativo, impraticável implementar, corrigir, achar algo de forma escalável, pois terá rotina que atenderá a todo módulo.
Cenário 3 - Datamodule por Form, haja memória, mito, para mim é a melhor forma a ser usada.
a) "Haja memória" porque? Se o datamodule só deve ser criado no Create form e liberado do Destroy? Se no EXE tem 1000 datamodule, cada um dele só ocupará memória quando ele for instanciado, e ao ser destruído será liberado a memória usada por ele, algo que não acontece nos cenários 1 e 2, tendo que deixa-lo por mais tempo ocupando memória para todos os forms do módulo use.
b) Manutenção o código limpo, só com o necessário para aquele form, eventos dos componentes poucos e enxutos, seguindo padrão de projeto ou seja "dê a Cesar o que é de Cesar"
Vamos a uma avaliação.
Um datamodule nada mais é que um contêiner, você sabe de quem um datamodule é herdado? Se não sabe, um datamodule é herdado de um TComponent, ué TComponent? isso mesmo, o pai do datamodule é o mesmo pai de todos os componentes que você usa no seu sistema, mas por ele ter sua característica de um form, muitos restringe seu uso, datamodule não tem nada a vê com form, sua hierarquia é muito distante, veja a raiz até chegar em um Form.
TComponent
|_TControl
|_TWinControl
|_TScrollingWinControl
|_TCustomForm
|_TForm
TComponent
|_TControl
|_TWinControl
|_TScrollingWinControl
|_TCustomForm
|_TForm
Um form precisa além dos componentes de acesso a dados e entre outros que necessários, do código de seus eventos e suas regras de negócio (regras de negócio jamais no datamodule), então se temos um datamodule para cada form o form terá só esse component a mais na memória além do que já irá precisar tendo o datamodule ou não, o que acontece no cenário 1 e 2.
Bem, disse acima, regras de negócio jamais no datamodule, então como proceder? Simples usando padrões de projeto e criando classe com as regras negócio para cada necessidade e linkando os eventos dos componentes que estão no datamadule aos métodos criados na classe.
Exemplo
TClientDataSet para Cliente no TDatamodule, nele um evento ClienteBeforePost(Dataset: TDataSet)
type
TClienteClassRegra = class
public
class procedure ClienteBeforePost(Dataset: TDataSet);
end;
...
procedure TClienteClassRegra.ClienteBeforePost(Dataset: TDataSet)
begin
// Regra de negócio aqui
end;
No TDatamudule só o código do evento, chamando o método da classe, deixando assim o datamodule limpo e a regra livre para serem usados em qualquer outro lugar quando preciso.
procedure TDataModule.ClienteBeforePost(Dataset: TDataSet) begin TClienteClassRegra.ClienteBeforePost(Dataset); end;E assim definindo métodos para cada evento usado, inclusive classe para eventos dos TFields como SetText, GetText, OnValidate etc..., tendo a classe, ela pode ser usada em vários datamodules, pois cada um só terá o ponteiro linkado, disparando a regra na classe.
Exemplo:
type
TClienteFieldRegra = class
public
class procedure ClienteFieldNameGetText(Sender: TField; var Text: string;
DisplayText: Boolean);
end;
...
procedure TDataModule.ClienteFieldNameGetText(Sender: TField;
var Text: string; DisplayText: Boolean); begin TClienteClassRegra.ClienteFieldNameGetText(Sender, Text, DisplayText); end;Para melhorar ainda mais esse desacoplamento, indico o não uso de TField em Designer, crie-os em run-time, já faço isso a muitos anos, e tem algo que pode fazer isso para você de forma simples, conheça e usar o ORMBr.
segunda-feira, 17 de abril de 2017
10:19
ORMBr - Versão 1.3.3 (Abr 2017)
- Melhoria - Implementado recurso para atualizar dados da tabela externa com relacionamento OneToOne quando a coluna chave de relacionamento for mudada.
- Melhoria - Otimização no método Open(), para que o SELECT seja construído somente uma vez.
- Melhoria - Refatoração nos métodos Open() e Find(), para aceitarem o parâmetro ASQL como String.
- Melhoria - Renomeado método GetNextPacket para NextPacket.
- Melhoria - Liberado o método NextPacket, para ser chamado pela aplicação, caso a propriedade AutoNextPacket = False;
- Melhoria - Refatoração nos métodos DisableDataSetEvents e EnableDataSetEvents.
- Melhoria - Grande refatoração para aumento de performance, passando a usar mais informações mapeadas do objeto e menos RTTI.
- Correção - Ajuste feito para respeitar a paginação de registros, quando passado um comando SELECT pelo método Open() e Find() direto, não estava sendo feito paginação nenhuma.
- Novo - Atualização do demo que não usa dataset, mostrando como criar um campo Aggregate, direto na class totalizando determinado campo.
- Novo - Criado método FindWhere(AWhere: string), esse método adiciona a clausula WHERE ao final do comando SELECT montado, passando assim um filtro para restringir o retorno de registros do banco de dados em um TObjectList<M>
- Novo - Criado método OpenWhere(AWhere: string), esse método adiciona a clausula WHERE ao final do comando SELECT montado, passando assim um filtro para restringir o retorno de registros do banco de dados em um IDBResultSet.
- Novo - Criado a propriedade AutoNextPacket, para que o método NextPacket possa ser controlado pela aplicação, valor padrão é TRUE;
- Novo - Criado interface ICommandMonitor que irá monitorar todos os comandos executado pelo ORMBr e mostrar em uma tela o que foi executado. Funcionalidade mostrada no demo na pasta ..\ORMBr\Demo\Data\FireDAC.
- Novo - Driver TFactorySQLite para acesso nativo ao SQLite, o driver usa componente de terceiro, as units agora fazem parte do projeto ORMBr e está na pasta ..\ORMBr\Source\External\SQLite, podem ser usadas sem precisar instalar o componente na IDE, basta instânciar o componente direto na aplicação.
Exemplo :
FDatabase := TSQLiteDatabase.Create(Self);
FDatabase.Filename := '..\Database\database.db3';
segunda-feira, 3 de abril de 2017
13:04
ORMBr - Conhecendo Formas de Obter Dados do Database
Veja as possíveis formas de obter dados do Database pelo ORMBr para popular um DataSet em memória.
Declare uma variável do tipo da interface de DataSet
var
oMemTable: IContainerDataSet;
Instâncie a interface, aqui vou usar TFDMemTable do FireDAC, mas temos ainda TClientDataSet até a data de hoje.
begin
oMemTable := TContainerFDMemTable.Create(oConn, MyFDMem);
Agora vou mostrar as formas que podemos fazer a abertura para que os dados sejam capturados do banco de dados e populem o FDMemTable em memória.
begin
// 1a Forma - Traz os dados da tabela Master do banco e popula o FDMemTable
// em memória.
oMemTable.DataSet.Open;
// 2a Forma - Traz o registro com ID = 5 e popula o FDMemTable em memória.
oMemTable.DataSet.Open(5);
// 3a Forma - Você quem define o comando SELECT usando a interface ICriteria.
oMemTable.DataSet.Open(CreateCriteria.Select.All
.From('Master')
.Where('master_id >= 5')
.OrderBy('description'));
quinta-feira, 16 de fevereiro de 2017
04:31
TAXTaskDialog - BrComponentes
Seja bem vindo, e ótima leitura.
A partir da versão do Delphi 2007, foi adicionado na VCL o TTaskDialog, o qual só terá o efeito visual se você estiver rodando sua aplicação no Windows Vista ou superior. Nós desenvolvedores, queremos sempre coisas novas para podermos repassar para os clientes e conquistá-los sempre mais com um produto de qualidade, visual atraente e facilidade, por isso desenvolvi o TAXTaskDialog.
O TAXTaskDialog é um componente que dará a sua aplicação uma melhor aparência, independente da versão do Windows que você estiver rodando sua aplicação usando ele, ele é um componente não visual, e pode ser parametrizado através do Object Inspector na IDE do delphi, tanto quanto via código. Disponibilizei a um tempo atras, no meu canal ORMBr no Instagram, canal esse que tratamos sobre um ORM criado por mim, e que é open source, quem tiver interesse em participar o link é https://t.me/canalormbr e também temos o grupo ORMBr onde discutimos e trocamos conhecimentos o link é https://t.me/ormbr, agora criei um repositório no Git e disponibilizei os fontes juntamente com o pacote de instalação do componente TAXTaskDialog, minha ideia é depois mudar seu nome para TBrTaskDialog, e nesse repositório disponibilizar uma suite de componentes bons juntamente com seus fontes, assim quem tiver interesse poderá baixa-los e usa-los, junto com os fontes do TAXTaskDialog, seguirá um demo, ele mostrará além de vários usos as duas formas de parametrização, via Object Inspector e via código.
A baixo mostro um exemplo via código e uma imagem do resultado.
A partir da versão do Delphi 2007, foi adicionado na VCL o TTaskDialog, o qual só terá o efeito visual se você estiver rodando sua aplicação no Windows Vista ou superior. Nós desenvolvedores, queremos sempre coisas novas para podermos repassar para os clientes e conquistá-los sempre mais com um produto de qualidade, visual atraente e facilidade, por isso desenvolvi o TAXTaskDialog.
O TAXTaskDialog é um componente que dará a sua aplicação uma melhor aparência, independente da versão do Windows que você estiver rodando sua aplicação usando ele, ele é um componente não visual, e pode ser parametrizado através do Object Inspector na IDE do delphi, tanto quanto via código. Disponibilizei a um tempo atras, no meu canal ORMBr no Instagram, canal esse que tratamos sobre um ORM criado por mim, e que é open source, quem tiver interesse em participar o link é https://t.me/canalormbr e também temos o grupo ORMBr onde discutimos e trocamos conhecimentos o link é https://t.me/ormbr, agora criei um repositório no Git e disponibilizei os fontes juntamente com o pacote de instalação do componente TAXTaskDialog, minha ideia é depois mudar seu nome para TBrTaskDialog, e nesse repositório disponibilizar uma suite de componentes bons juntamente com seus fontes, assim quem tiver interesse poderá baixa-los e usa-los, junto com os fontes do TAXTaskDialog, seguirá um demo, ele mostrará além de vários usos as duas formas de parametrização, via Object Inspector e via código.
A baixo mostro um exemplo via código e uma imagem do resultado.
var TskDlg: TAxTaskDialog; begin TskDlg := TAxTaskDialog.Create(nil); try TskDlg.TitleColor := clLime; TskDlg.TitleFont.Color := clBlack; TskDlg.Caption := 'Sistemas Axial'; TskDlg.Title:= 'Tem certeza que deseja entrar em alteração?'; TskDlg.Text := 'Esta opção entra em ateração do registro selecionado'; TskDlg.FooterText := 'Selecione uma opção ou cancele a operação'; TskDlg.CommonButtons := [tcbNone]; TskDlg.MainIcon := tdiQuestion; TskDlg.FooterIcon := tdiWarning; TskDlg.Flags := [tfUseCommandLinks]; TskDlg.MetroStyle.TaskDialogMetro := True; TskDlg.MetroStyle.TaskDialogColor := clGray; TskDlg.MetroStyle.TaskDialogFontColor := clWindow; with TaxTaskDialogButtonItem(TskDlg.Buttons.Add) do begin Caption := '&Sim'; CommandLinkHint := 'Esta opção você entrará no modo de edição'; end; with TaxTaskDialogButtonItem(TskDlg.Buttons.Add) do begin Caption := '&Não'; CommandLinkHint := 'Esta opção você não entrará no modo edição'; end; TskDlg.Execute; if TskDlg.ButtonResult <> 0 then Abort; finally TskDlg.Free; end;
Abaixo segue outra imagem do resultado em execução do TAXTaskDialog bem completo, sua parametrização foi feita via IDE do Delphi no Object Inspector, vocês poderão analisa-la no demo.
O Link do repositório git é https://bitbucket.org/ProjetosBr/componentesbr
quarta-feira, 23 de novembro de 2016
11:05
ORMBr - Conhecendo o Outro Lado
O combustível do ORMBr sempre será as classes modelos, e para que tenhamos alto desempenho, precisamos conhecer o que adicionar a esses modelos para que tenhamos sincronização com nosso banco de dados.
Apresento aqui para vocês as correspondências entre os tipos usados pelo ORMBr e os tipos criados no seu banco dados já existente.
Apresento aqui para vocês as correspondências entre os tipos usados pelo ORMBr e os tipos criados no seu banco dados já existente.
procedure TFieldTypeRegister.GetFieldTypeDefinition(AColumn: TColumnMIK);
begin
case AColumn.FieldType of
ftByte, ftShortint, ftSmallint, ftWord:
begin
AColumn.TypeName := 'SMALLINT';
end;
ftInteger, ftLongWord:
begin
if FDriverName = dnMSSQL then AColumn.TypeName := 'INT'
else if FDriverName = dnMySQL then AColumn.TypeName := 'INT'
else AColumn.TypeName := 'INTEGER';
end;
ftLargeint: AColumn.TypeName := 'NUMERIC(%l)';
ftString: AColumn.TypeName := 'VARCHAR(%l)';
ftWideString: AColumn.TypeName := 'NVARCHAR(%l)';
ftFixedChar: AColumn.TypeName := 'CHAR(%l)';
ftFixedWideChar: AColumn.TypeName := 'NCHAR(%l)';
ftDate: AColumn.TypeName := 'DATE';
ftTime: AColumn.TypeName := 'TIME';
ftDateTime: AColumn.TypeName := 'DATETIME';
ftTimeStamp: AColumn.TypeName := 'TIMESTAMP';
ftFloat:
begin
if FDriverName = dnMSSQL then AColumn.TypeName := 'FLOAT'
else if FDriverName = dnMySQL then AColumn.TypeName := 'FLOAT'
else if FDriverName = dnPostgreSQL then AColumn.TypeName := 'NUMERIC(%p,%s)'
else AColumn.TypeName := 'DECIMAL(%p,%s)';
end;
ftSingle: AColumn.TypeName := 'REAL';
ftExtended:
begin
if FDriverName = dnMSSQL then AColumn.TypeName := 'DOUBLE'
else if FDriverName = dnMySQL then AColumn.TypeName := 'DOUBLE'
else AColumn.TypeName := 'DOUBLE PRECISION';
end;
ftCurrency:
begin
if FDriverName = dnMSSQL then AColumn.TypeName := 'MONEY'
else if FDriverName = dnMySQL then AColumn.TypeName := 'DECIMAL(%p,%s)'
else AColumn.TypeName := 'NUMERIC(%p,%s)';
end;
ftBCD, ftFMTBcd:
begin
if FDriverName = dnPostgreSQL then AColumn.TypeName := 'MONEY'
else if FDriverName = dnMSSQL then AColumn.TypeName := 'MONEY'
else AColumn.TypeName := 'DECIMAL(%p,%s)';
end;
ftMemo:
begin
if FDriverName = dnFirebird then AColumn.TypeName := 'BLOB SUB_TYPE TEXT'
else AColumn.TypeName := 'LOGBLOB';
end;
ftWideMemo, ftBlob:
begin
if FDriverName = dnFirebird then AColumn.TypeName := 'BLOB SUB_TYPE TEXT'
else AColumn.TypeName := 'TEXT';
end;
else
raise Exception.Create('Tipo da coluna definida, não existe no ORMBr.');
end;
end;
Dependendo do tipo definido na propriedade da sua classe modelo, o ORMBr irá identificar o tipo do campos no seu banco de dados, exemplo, se definirmos a propriedade do tipo ftWideMemo ou ftBlob, o ORMBr irá identificar que no seu banco dados a coluna é BLOB SUB_TYPE TEXT no caso o banco seja Firebird caso contrário irá identificar como TEXT para os demais bancos.
Vemos aqui que o tipo definido no ORMBr, poderá se comportar diferente dependendo do banco usado, então pessoal atenção a esse código, qualquer situação adversa me comunique, pois acredito que não pensei em todas as situações e tipos.
Vemos aqui que o tipo definido no ORMBr, poderá se comportar diferente dependendo do banco usado, então pessoal atenção a esse código, qualquer situação adversa me comunique, pois acredito que não pensei em todas as situações e tipos.
10:48
ORMBr - Ao Usar, Perdemos em Performance?
Muitos pensam que usar o ORMBr perderia performance, gente o ORMBr trabalho com duas linhas de frente para vocês.
1a ) Ele fará de forma SUPER simples TUDO o que você teria que fazer manual, como SELECT, Adicionar TFields e configurar um a um, gerenciar abertura de subtabelas em mestre-detalhe, TUDO isso passa a ser automatizado.
2a) Ele fará de forma SURPER simples tudo o que os componentes DataSet já faz, pois o que você achar que um TFDQuery faz, quando você alimenta os TFields dele, em seguida dispara um Post e um ApplyUpdate?
Simplesmente montam o comando SQL internamente e mandam para o banco, é exatamente o que o ORMBr faz também.
Se é assim que funciona, como podemos perder performance ?
03:26
ORMBr - TFields em Runtime
Em 2006 palestrei na Borcon e minha palestra foi sobre Multicamadas com Multibancos, na época só conseguia aplicar multibancos através de uma técnica criada por mim, que foi a criação de TFields em runtime.
A Criação de TFields em Designer além de ser um CAUS para manutenções futuras em projetos, me trazia um problema de incompatibilidade entre os tipos de TFields que o Delphi criava para bancos diferentes, exemplo o tipo data, e té hoje isso acontece, só com a aquisição do FireDAC passou a ter um recurso nativo de mapeamento de tipos para os TFields, criados em designer, recurso esse que tem a mesma finalidade da que criei a mais de 10 anos atrás, resolver incompatibilidade de tipos em bancos diferentes.
Porém a técnica usada por mim, elimina ainda outras situações como a manutenções futuras no projeto, mas que manutenções são essas que você diz Isaque?
Se criar um campo no banco VARCHAR(10) em designer será criado um TField do tipo TStringField de size 10, esse TField pode ter sido adicionados em vários pontos do meu projeto, tela de cadastro, consultas etc..., se algum dia eu precisar mudar o tamanho desse campo no banco para 15, terá que lembrar todos os pontos do meu sistema que adicionou o TField para esse campo, caso contrário, mesmo no banco ele tendo tamanho 15, o delphi irá limitar a digitação em 10, esse é um dos exemplos simples, existem outras.
Com a técnica de criar TFields em runtime, esse problema é TOTALMENTE resolvido, pois o TField será criado com base no campo atual do banco, sendo criado sempre de forma atual.
Com o nascimento do ORMBr, isso ficou bem mais simples, pois além das grandes vantagens em agilidade que o ORMBr traz, ele trata, cria e configura cada TField em runtime, isso tudo com base no modelo, vejamos como podemos definir isso no modelo do ORMBr:
[Column('price', ftFloat, 18, 3)]
[Dictionary('Preço Unitário','Mensagem de validação','0','#,###,##0.00','',
taRightJustify)]
property price: Double Index 4 read Fprice write Fprice;
Vejamos os atributos:
Column : Informo o nome do campo, o tipo que quero e tamanho, pronto o ORMBr faz o resto
Dictionary : Informo o DisplayLabel, Mensagem de validação, Valor Default, DisplayFormat, EditMask, e o alinhamento.
Column : Informo o nome do campo, o tipo que quero e tamanho, pronto o ORMBr faz o resto
Dictionary : Informo o DisplayLabel, Mensagem de validação, Valor Default, DisplayFormat, EditMask, e o alinhamento.
terça-feira, 8 de novembro de 2016
03:34
Técnica Para Ajudar no Dia Dia
Seja bem vindo a mais esse artigo, e boa leitura.
Desenvolvedores, vive seu dia dia escrevendo código, mas claro o foco sempre na lógica e na melhor forma de fazer, e na maioria das vezes tem que recorrer a uma ajudinha, seja ela no help da linguagem ou no Google, para lembrar da sintaxe correta de um comando, procedure ou função.
O sábio não é aquele que sabe e faz tudo, mas aquele que lembra que existe, e tem a coragem de procurar, e se não existe, a coragem de estudar para conseguir aprender e fazer.
Existem situações das quais ao escrever um código, nos deparamos com a dúvida e o esquecimento de até mesmo o que nós criamos, exemplo o nome de uma coluna no banco de dados, e é nessa situação que vou passar uma dica de um possível recurso para ajudar no seu dia dia.
Em um ponto do código, precisa escrever um comando SQL, do qual vai selecionar varias colunas de uma determinada tabela do banco de dados, então faz:
Em um ponto do código, precisa escrever um comando SQL, do qual vai selecionar varias colunas de uma determinada tabela do banco de dados, então faz:
'SELECT TableName.Codigo, TableName.Nome, TableName.Endereco FROM TableName'
Simples, mas nem toda vez irá lembrar de todos os nomes e de todas as tabelas do banco de dados, dai tende a parar, e ir olhar no banco qual o nome correto para a determinada coluna, e quando esse banco for dados manutenção por mais de uma pessoa, só tende piorando.
Você já pensou em uma técnica para te ajudar no dia dia nesse caso? Não, então vou te dar uma dica, segue abaixo:
...
Type
TMyTable = class
private
class function GetTableName: string;
class function GetCodigo: string;
class function GetNome: string;
class function GetEndereco: string;
public
class property TableName: string read GetTableName;
class property Codigo: string read GetCodigo;
class property Nome: string read GetNome;
class property Endereco: string read GetEndereco;
end;
implementation
class function TMyTable.GetTableName: string;
begin
Result := 'TableName';
end;
class function TMyTable.GetCodigo: string;
begin
Result := 'TableName.Codigo';
end;
class function TMyTable.GetNome: string;
begin
Result := 'TableName.Nome';
end;
class function TMyTable.GetEndereco: string;
begin
Result := 'TableName.Endereco';
end;
end.
Usando a class: 'SELECT ' + TMyTable.Codigo + ',' +
TMyTable.Nome + ',' +
TMyTable.Endereco +
' FROM ' + TMyTable.TableName;
Qual a vantagem? como criamos a class, nela estará todas as propriedades com os nomes dos campos da tabela, então ao precisarmos podemos pedir a ajuda do Delphi ao recurso "Code Completion" e ele mostrará todos os possíveis nomes existentes na class, facilitando assim nossa busca.
quarta-feira, 2 de novembro de 2016
11:09
ORMBr - Gerenciamento DB (Interbase e PostgreSQL)
Seja bem vindo a mais esse artigo, e boa leitura.
Lancei hoje os drivers para gerenciamento de banco de dados para Interbase e PostgreSQL, já estão disponíveis no repositório, dúvidas, perguntas, bugs, sugestões, gentileza podem ser postados no Fórum http://www.ormbr.com.br/forum e os fontes podem ser baixados no site http://www.ormbr.com.br no menu Download.
Quero aqui deixar meus agradecimentos ao Juliomar Marchetti, mais informações sobre ele podes ser encontradas no seu blog http://www.juliomarmarchetti.com.br, ele foi quem teve a ideia e colocou mão na massa para aproximar os interessados no projeto ORMBr ao seu autor, ele criou um Canal e um Grupo no Telegram o link para o Canal https://telegram.me/canalormbr e para o Grupo https://telegram.me/ormbr, convido a todos interessados a participar.
O ORMBr já da suporta a gerenciamento a banco de dados com base no modelo criado, até o momento já temos os drivers para os bancos: MSSQL, MySQL, Firebird, Interbase, SQLite e PostgreSQL, o recurso oferecido até o momento são criação de tabelas com sua estrutura completa e com todos os recursos de coluna como TIPOS, NOT NULL, DEFAULT, juntamente com recursos como criação de PrimaryKey, ForeignKey, Indexe e Check, isso funcional e testado, e não acabou por ai, tem ainda o recurso de ADD COLUMN nova a estrutura, caso a coluna seja adicionado ao modelo e ser rodado o recurso de verificação de metadata, segue abaixo um exemplo de como usar o recurso:
procedure TForm1.Button1Click(Sender: TObject);
var
oManager: TDatabaseAbstract;
oConnection: IDBConnection;
begin
// Instância da class de conexão via FireDAC, segundo parametro
// o Driver de qual Banco usado
oConnection := TFactoryFireDAC.Create(FDConnection1, dnPostgreSQL);
oManager := TDatabaseManager.Create(oConnection);
oManager.BuildDatabase;
for cDDL in oManager.GetCommandList do
Memo1.Lines.Add(cDDL.Command);
oManager.Free;
end;
Nota: Até o momento a criação do banco de dados, tem que ser feito manualmente, estou estudando a implementação desse recurso via ORMBr, após a criação do banco vazio, só configura-lo ao engine de conexão que no ORMBr podem ser: FireDAC, DBExpress ou Zeos até agora, em seguida criar a fabrica de conexão conforme engine de preferência e rodas a atualização conforme modelo criado. Abaixo um exemplo de um modelo bem completo para estudo e teste:
unit ormbr.model.person;
interface
uses
Classes,
DB,
/// orm
ormbr.mapping.attributes,
ormbr.types.mapping,
ormbr.mapping.register;
type
[Entity]
[Table('Person','Tabela de pessoas')]
[PrimaryKey('Id', NoSort, False, 'Chave primária')]
[Indexe('IDX_FirstName','FirstName', NoSort, True, 'Indexe por nome')]
[Check('CHK_Age', 'Age >= 0')]
TPerson = class
private
{ Private declarations }
FId: Integer;
FFirstName: string;
FLastName: string;
FAge: Integer;
FSalary: Double;
public
{ Public declarations }
[Restrictions([NoUpdate, NotNull])]
[Column('Id', ftInteger)]
[Dictionary('Código ID','Mensagem de validação','0','','',taCenter)]
property Id: Integer Index 0 read FId write FId;
[Restrictions([NotNull])]
[Column('FirstName', ftString, 40)]
[Dictionary('Primeiro nome','Mensagem de validação','','','',taLeftJustify)]
property FirstName: String Index 1 read FFirstName write FFirstName;
[Column('LastName', ftString, 30)]
[Dictionary('Último nome','Mensagem de validação','','','',taLeftJustify)]
property LastName: String Index 2 read FLastName write FLastName;
[Restrictions([NotNull])]
[Column('Age', ftInteger)]
[Dictionary('Idade','Mensagem de validação','0','','',taCenter)]
property Age: Integer Index 3 read FAge write FAge;
[Restrictions([NotNull])]
[Column('Salary', ftCurrency, 18, 3)]
[Dictionary('Preço','Mensagem de validação','0','','',taRightJustify)]
property Salary: Double Index 4 read FSalary write FSalary;
end;
implementation
initialization
TRegisterClass.RegisterEntity(TPerson);
end.
terça-feira, 1 de novembro de 2016
06:34
ORMBr - Gerenciamento DB (Firebird e MySQL)
Seja bem vindo a mais esse artigo, e boa leitura.
Como prometido, subi hoje os drivers para gerenciamento de banco de dados para Firebird e MySQL, próximo passo será PostgreSQL, os demais estão disponíveis no repositório, dúvidas, perguntas, bugs, sugestões, gentileza postarem no Fórum, conto com a ajuda de todos para fazermos juntos do ORMBr, um grande e respeitado ORM Framework.
Baixe o ORMBr Framework
sexta-feira, 28 de outubro de 2016
16:32
ORMBr - Gerenciamento DB (MSSql e SQLite)
Seja bem vindo a mais esse artigo, e boa leitura.
Hoje quero passar para você, que o ORMBr agora conta com a 1a versão da camada de gerenciamento de banco de dados, após grande esforço e trabalho implementei o recurso para os bancos SQLite e SQLServer, logo logo sairá para Firebird e MySQL, essa versão que já está disponível no repositório você pode baixar pelo link www.ormbr.com.br menu Download.
Nessa novidade temos a criação completa de tabela, PrimaryKey, ForeignKeys, Indexes e Checks, e ainda a adição de novos campos caso adicionados no modelo, e não exista no banco. Tem bastante recurso a ser feito, mas um passo a cada dia chegaremos ao nosso destino desejado, que é o gerenciamento total ao banco, pretendo ir até onde for possível, ir além de alguns ORMs do mercado como gerenciamento de Views, Triggers (esses já bem avançados) e quem sabe até Store de Procedures, mesmo que cada banco tendo sua sintaxe especifica, trabalho dará, mas acredito que é possível sim, por que não?
Tenho uma frase que marcou muito minha vida de Albert Einstein "A mente que se abre a uma nova ideia jamais voltará ao seu tamanho original", então quero que você pense nessa frase, e abra sua mente para entender os benefícios que o ORMBr pode trazer para sua vida, no que diz respeito a desenvolvimento, agilizando, dando confiabilidade e economizando em algumas dezenas e quem sabe centenas de linhas.
O ORMBr é puro delphi, você não deve ter medo usa-lo, no inicio por seguir padrões de projetos, ele pode parecer complexo, mas acreditem, não é, e um ditado cabe bem nessa afirmação, "quem vê cara não vê coração", o ORMBr tem seu código extremamente simples, ele usa Dataset nativo do Delphi, ele faz o mesmo que você faz no seu código já existente do seu dia ia, mas de forma extremamente mais simples, e econômico, pois esse mesmo código servirá para todo o seu projeto, o que é preciso, é de dedicação para testa-lo, debuga-lo e entender seu funcionamento, e dai terá a confiança do que estou falando.
Abaixo um exemplo de um modelo bem completo, que servirá como base para o ORMBr para gerenciamento do banco de dados, nele teremos a criação de uma tabela completa com todos os atributos das colunas, uma PrimaryKey, um Indexe, um Check, esse mesmo modelo ainda servirá para definição dos TFields criados no Dataset usado, isso tudo feito automaticamente para ORMBr, de forma simples e eficaz, veja abaixo:
unit ormbr.model.person;
interface
uses
Classes,
DB,
/// orm
ormbr.mapping.attributes,
ormbr.types.mapping,
ormbr.mapping.register;
type
[Entity]
[Table('Person','Tabela de pessoas')]
[PrimaryKey('Id', NoSort, False, 'Chave primária')]
[Indexe('IDX_FirstName','FirstNome', NoSort, True, 'Indexe por nome')]
[Check('CHK_Age', 'Age >= 0')]
TPerson = class
private
{ Private declarations }
FId: Integer;
FFirstNome: string;
FLastNome: string;
FAge: Integer;
FSalary: Double;
public
{ Public declarations }
[Restrictions([NoUpdate, NotNull])]
[Column('Id', ftInteger)]
[Dictionary('Código ID','Mensagem de validação','0','','',taCenter)]
property Id: Integer Index 0 read FId write FId;
[Restrictions([NotNull])]
[Column('FirstNome', ftString, 40)]
[Dictionary('Primeiro nome','Mensagem de validação','','','',taLeftJustify)]
property FirstNome: String Index 1 read FFirstNome write FFirstNome;
[Column('LastNome', ftString, 30)]
[Dictionary('Último nome','Mensagem de validação','','','',taLeftJustify)]
property LastNome: String Index 2 read FLastNome write FLastNome;
[Restrictions([NotNull])]
[Column('Age', ftInteger)]
[Dictionary('Idade','Mensagem de validação','0','','',taCenter)]
property Age: Integer Index 3 read FAge write FAge;
[Restrictions([NotNull])]
[Column('Salary', ftFloat, 18, 3)]
[Dictionary('Preço','Mensagem de validação','0','','',taRightJustify)]
property Salary: Double Index 4 read FSalary write FSalary;
end;
implementation
initialization
TRegisterClass.RegisterEntity(TPerson);
end.
No próximo artigo, vou falar para você tudo sobre os atributos do ORMBr, quais seus paramtros e para que serve cada um deles, verá que o ORMBr terá total controle com base no modelo criado, te proporcionado total funcionalidades de forma simples para ser usado.
quarta-feira, 19 de outubro de 2016
08:31
ORMBr - Criando Lookup Field
No delphi desde sempre existiu o lookup field, e como não podemos deixar no ORMBr podemos criar lookup field de forma simples, é o que vamos mostrar nesse artigo de hoje.
No nosso modelos teremos uma propriedade que receberá o ID da tabela lookup, ficando assim o exemplo:
Também teremos a tabela lookup, que mostrará todos os seus registros para que possamos selecionar um, vou representa-la pela variável oLookup, ficando assim o exemplo:
AKeyFields: Nome do campo que receberá o valor do campo que será definido em LookupKeyFields que virá da tabela lookup;
ALookupDataSet: A variável que foi instanciada e terá os registros lookup, no nosso caso oLookup;
ALookupKeyFields: Nome do campo chave que será o retorno da tabela lookup, para ser armazenado no AKeyFields;
ALookupResultField: Nome do campo result para ser visualizado.
No nosso modelos teremos uma propriedade que receberá o ID da tabela lookup, ficando assim o exemplo:
...
[Column('detail_lookup_id', ftInteger)]
[Dictionary('detail_lookup_id','Mensagem de validação','','','',taCenter)]
property detail_lookup_id: Integer Index 0 read Flookup_id write Flookup_id;
...
Continuando, teremos a tabela que irá receber o ID da tabela lookup que vou representa-la pela variável oDetail, ela é quem terá a propriedade acima no seu modelo.Também teremos a tabela lookup, que mostrará todos os seus registros para que possamos selecionar um, vou representa-la pela variável oLookup, ficando assim o exemplo:
...
var
oLookup: IContainerDataSet< tlookup >;
oDetail: IContainerDataSet< tdetail >;
begin
oDetail := TContainerClientDataSet< tdetail >.Create(oConn, CDSDetail);
oLookup := TContainerClientDataSet< tlookup >.Create(oConn, CDSLookup);
oDetail.DataSet.AddLookupField('lookup_field',
'detail_lookup_id',
oLookup.DataSet,
'lookup_id',
'lookup_description');
...
Observe que as variáveis oDetail e oLookup, foram instanciadas recebendo dois parâmetros, de conexão e um TClientDataset para fazer cache, até ai normal como já mostrado em outro artigo.
O segredo está aqui nessa linha: oDetail.DataSet.AddLookupField('lookup_field',
'detail_lookup_id',
oLookup.DataSet,
'lookup_id',
'lookup_description');
Como o campo ID será recebida pela tabela oDetail como falei acima, o campo lookup será criado nela, chamando o método AddLookupField, esse método receberá todos os parâmetros necessários para configurar um TField do tipo Lookup, os parâmetros são:
procedure AddLookupField(AFieldName: string;
AKeyFields: string;
ALookupDataSet: TObject;
ALookupKeyFields: string;
ALookupResultField: string);
AFieldName: Nome para o TField campo; AKeyFields: Nome do campo que receberá o valor do campo que será definido em LookupKeyFields que virá da tabela lookup;
ALookupDataSet: A variável que foi instanciada e terá os registros lookup, no nosso caso oLookup;
ALookupKeyFields: Nome do campo chave que será o retorno da tabela lookup, para ser armazenado no AKeyFields;
ALookupResultField: Nome do campo result para ser visualizado.
terça-feira, 11 de outubro de 2016
09:52
ORMBr - Criando um Mestre-Detalhe
Mais uma dica do ORMBr.
Vamos hoje demonstrar como criar um mestre-detalhe de forma simples e eficaz, usando o ORMBr.
1o Passo: Criar a conexão com já mostrado no post ORMBr - Como criar uma conexão ?
2o Passo: Adiciona em seu form dois TClientDataSet (podemos usar o TFDMemTable), vou usar o TClientDataSet nessa dica, adicione também dois TDataSource, em seguida configure suas propriedades ligando cada um ao seu TClientDataSet.
3o Passo: Adicione na clausula USES, as units:
5o Passo: Defina duas variáveis do tipo IContainerDataSet<T>, onde <T> devem ser os tipos dos modelos criados para mestre e detalhe, veja o código exemplo:
Vamos hoje demonstrar como criar um mestre-detalhe de forma simples e eficaz, usando o ORMBr.
1o Passo: Criar a conexão com já mostrado no post ORMBr - Como criar uma conexão ?
2o Passo: Adiciona em seu form dois TClientDataSet (podemos usar o TFDMemTable), vou usar o TClientDataSet nessa dica, adicione também dois TDataSource, em seguida configure suas propriedades ligando cada um ao seu TClientDataSet.
3o Passo: Adicione na clausula USES, as units:
ormbr.dependency.injection.clientdataset, ormbr.dependecny.interfaces, ormbr.factory.dbexpress; // <= Aqui a fábrica de conexão escolhida por você.4o Passo: Crie os modelos do mestre e do detalhe, veja o demo que segue junto aos fontes caso tenha dúvida nesse passo.
5o Passo: Defina duas variáveis do tipo IContainerDataSet<T>, onde <T> devem ser os tipos dos modelos criados para mestre e detalhe, veja o código exemplo:
oMestre: IContainerDataSet<TMestre>; oDetalhe: IContainerDataSet<TDetalhe>;6o Passo: No Create do Form, instancie a variável oMestre definida, passando para ela a variável de conexão, e o TClientDataSet1 que foi adicionado no inicio, veja o exemplo:
oMestre := IContainerDataSet<TMestre>.Create(oConn, ClientDataSet1);7o Passo: Também no Create do Form, instancie a variável oDetalhe definida, passando para ela a variável de conexão, e o TClientDataSet2 que foi adicionado no inicio e um terceiro parâmetro informando quem é o objeto MESTRE, veja o exemplo:
oDetalhe := IContainerDataSet<TDetalhe>.Create(oConn, ClientDataSet2, oMestre);8o Passo: Abra a tabela, chamando o método Open, veja o exemplo:
oMestre.DataSet.Open;A partir desse ponto, o ORMBr gerencia todo o resto, como abrir, relacionar, excluir e fechar a tabela DETALHE automaticamente.
terça-feira, 27 de setembro de 2016
13:29
ORMBr - Select com paginação de registros.
Sabemos que banco de dados nenhum, conseguirá oferecer seus benefícios, em questão aqui sua velocidade de busca, se além de não for bem arquitetado, também for usado de forma incoerente, por um sistema mal projetado.
No ORMBr, temos o recurso de paginação para resolver isso, quando formos fazer um select de muitos registros, paginação é um recurso fundamental para que o sistema reflita a velocidade de retorno, o qual o banco de dados não faria sozinho, para definirmos esse recurso no ORMBr, usaremos um terceiro parâmetro na class de conexão.
No ORMBr, temos o recurso de paginação para resolver isso, quando formos fazer um select de muitos registros, paginação é um recurso fundamental para que o sistema reflita a velocidade de retorno, o qual o banco de dados não faria sozinho, para definirmos esse recurso no ORMBr, usaremos um terceiro parâmetro na class de conexão.
// DBExpress de 10 em 10 oConnection := TFactoryDBExpress.Create(SQLConnection1, dnSQLite, 10); // ZeosLib de 50 em 50 oConnection := TFactoryZeos.Create(ZConnection1, dnSQLite, 50); // FireDAC de 100 em 100 oConnection := TFactoryFireDAC.Create(FDConnection1, dnSQLite, 100);Demostrei em cada tipo de fábrica que pode ser usado no ORMBr, um valor diferente, para ficar bem claro que você é quem decidirá a paginação desejada, trazendo assim agilidade nos selects de seu sistema, principalmente se seu cliente tenha uma rede precária.









