Dicas sobre desenvolvimento de software, gestão e tributações

Rede Social

18 de agosto de 2020

C#: Limitando retorno de registros LINQ


 Seguindo com o LINQ vamos ver hoje como limitar o número de registros.

Caso não tenha visto os posts anteriores sugiro que dê uma conferida, neles falamos de Ordenação e Agregação.


Tendo como base a mesma classe e lista do exemplo anterior:

Aula
{
    Id int
    NomeAula string
    Curso int
    TempoDuracao datetime
}

List<Aula> aulas;

Imagine que quero saber quais são as 5 aulas com maior tempo de duração, primeiramente tenho que ordenar pelo tempo de duração, no caso como quero as de maior tempo a ordenação é descendente (do maior para o menor) e utilizo o método Take passando 5 como parâmetro.

var cursos = db.Cursos.OrderByDescending(c => c.TempoDuracao).Take(5);


Ou caso eu queira apenas a de maior tempo de duração, mas quero também me certificar de que caso eu não tenha nenhuma aula cadastrada no curso não me retorne um erro, uso o método FirstOrDefault. E indico sempre usá-lo ao invés do First como garantia, por mais que saiba que a lista tenha valores.

var curso = db.Cursos.OrderByDescending(c => c.TempoDuracao).FirstOrDefault();

Ler

13 de agosto de 2020

Instalando o Ubuntu Server 20.04 LTS no Oracle VM VirtualBox


 

 

No post de hoje mostraremos uma maneira bem básica de se criar um servidor Ubuntu no Oracle VM VirtualBox.

Apesar da popularização dos ambientes em nuvem, uma VM não deixa de ser uma opção bem interessante para ambientes de desenvolvimento e/ou aprendizagem. Eu mesmo gosto bastante de criar VMs quando quero testar algum OS diferente, ou realizar alguns testes que podem acabar "crashando" o OS, ou ainda quando estou desenvolvendo algum projeto. Neste último caso eu geralmente configuro uma VM como um espelho do ambiente que terei em produção. Com isso posso realizar vários testes a vontade, sem me preocupar se vou ou não fazer alguma besteira, uma vez que basta voltar para o último snapshot válido, ou, no pior dos casos, reinstalar a VM.

Bom, mas chega de falação e vamos ao que interessa!

Antes de mais nada você precisará baixar e instalar o Oracle VM VirtualBox. Você pode baixar clicando aqui, ou pela loja de apps do seu OS.

Neste post não iremos mostrar como instalar o VirtualBox, mas é basicamente o padrão Next, Next, Next...

Uma observação importante! Talvez seja necessário que você habilite a configuração de virtualização na BIOS do seu computador.

 

O Ubuntu Server pode ser baixado clicando aqui, ou, se preferir, pelo site oficial https://ubuntu.com/.

 

Ao abrir o Oracle VM VirtualBox, você verá uma tela similar a esta:

 

Vamos agora criar a nossa VM clicando em Novo

Aqui iremos fazer a configuração básica da nossa VM, dar um nome, dizer o local onde os arquivos da VM ficarão salvos, o tipo do OS e a versão do OS (geralmente essas informações serão sugeridas de acordo com o nome que você der a sua VM). Também devemos informar a quantidade de memória RAM (neste caso vou usar 4GB) e se iremos criar um HD virtual ou utilizar um existente (ou não utilizar nenhum). Neste caso criaremos um novo.


Feito essas configurações, clicaremos em "Criar".

Agora a configuração é relacionada ao HD. Basicamente pede-se que informemos onde será salvo o HD virtual, o tamanho, o tipo e se será alocado dinamicamente ou não. Usaremos as configurações padrão, então basta clicar em "Criar".

 

Pronto! Com isso temos nossa configuração base. Agora vamos para a instalação do OS. Basta "Iniciar" a VM.


Ao iniciarmos, a primeira coisa que precisaremos fazer é informar o local da ISO que baixamos anteriormente. Após isso podemos então iniciar a instalação clicando em "Iniciar".


O processo será iniciado com o Ubuntu fazendo algumas checagens. E após isso, com tudo estando OK, ele pedirá para que selecionemos o idioma de instalação.

Obs: A partir daqui toda as configurações serão feitas pelo teclado.

Selecione o idioma desejado através das setas do teclado e pressione "Enter".


O próximo passo é selecionar o layout do teclado. Provavelmente o Ubuntu já conseguiu identificar sozinho, mas caso não basta alterar a configuração para a do seu teclado.


A próxima configuração é a de rede. Manteremos a configuração padrão.


Agora nos é pedido uma configuração de proxy. Caso você utilize algum proxy, basta informá-lo no respectivo campo. Senão, basta seguir com a instalação.


A próxima configuração é a do mirror do Ubuntu. De maneira simples, este mirror é onde está localizado o repositório do Ubuntu. Aqui temos uma lista dos principais mirrors disponíveis por país. Mas não é necessário alterar esta configuração, portanto apenas continuaremos com a instalação.


Chegamos agora na configuração do storage do sistema. Aqui podemos particionar o disco que criamos anteriormente como bem entendermos. Porém, como não é a intenção deste post falar sobre sistemas de arquivos e partições, iremos adotar a configuração sugerida na instalação.


Temos agora o resumo das configurações do storage.


Ao seguir com a instalação será exibida uma mensagem de confirmação com alguns alertas sobre a instalação.


O próximo passo é informar os nossos dados de usuário e o nome do nosso computador.


Temos agora a opção de instalar um servidor OpenSSH. Como também não é intenção deste post falar sobre SSH, continuaremos o processo sem instalar o OpenSSH


Por fim, temos a possibilidade de instalar vários outros recursos, como por exemplo o aws-cli, que realiza integração com o Amazon AWS, ou o cliente para ingreção com o Heroku, entre outros. Caso você utilize algum dos serviços listados, você pode selecioná-los neste momento. Ou também pode instalá-los posteriormente.


A partir deste momento a instalação será iniciada, e, quando for finalizada, será solicitado que reiniciemos a máquina.

Obs: É comum acontecer um erro na hora de reiniciar, geralmente quando o sistema tenta "desmontar" a ISO. Caso isso ocorra com você, basta pressionar "Enter" que o sistema irá reiniciar normalmanete. Mas se mesmo assim o sistema não reiniciar, basta fechar a janela pedindo para desligar a máquina, e então iniciar novamente o servidor.


Pronto! Após a reinicialização poderemos logar no sistema utilizando o usuário que criamos durante a instalação.


Mas antes de finalizarmos o post aqui, vamos criar um snapshot do nosso servidor. Então vamos começar desligar nosso servidor digitando o comando "shutdown now".

Quando o servidor for desligado, sua janela será fechada automaticamente.

Voltamos agora para o VirtualBox e vamos clicar nas opções do nosso servidor e selecionar a opção "Snapshots".


Basta então clicar "Criar". Será pedido para darmos um nome para nosso snapshot, assim como uma descrição.


Feito! A partir daqui podemos utilizar nosso servidor recém criado, e caso haja algum problema, basta restaurar este snapshot.

 

É interessante sempre criar snapshots antes e após alterações relevantes do sistema, como uma atualização, por exemplo. Isso fará com que não tenhamos muitos "prejuízos" se precisarmos restaurar o sistema.


E com isso finalizamos nosso post! Até a próxima!

Ler

11 de agosto de 2020

C#: Funções de agregação LINQ


Seguindo o post anterior de LINQ sobre ordenações  vamos ver algumas funções de agregação.

Tendo como base a mesma classe e lista do exemplo anterior:

Aula
{
    Id int
    NomeAula string
    Curso int
    TempoDuracao datetime
}

List<Aula> aulas;

Primeiramente quero saber quais aulas tem o maior tempo, a que tem o menor tempo e a média de tempo de todas elas.

Para saber a de maior usarei o Max:
var max = aulas.Max(c => c.TempoDuracao);

Para saber a de menor o Min
var min = aulas.Min(c => c.TempoDuracao);

E para a média o Average
var media= aulas.Average(c => c.TempoDuracao);

Uma outra opção bem interessante é contar quantos registros existem seguinte uma regra que eu definir, por exemplo, quero saber quantas aulas tem Engenharia no nome, para isso utilizo o Count para contar e dentro dele utilizo o Contains para comparar as strings.
int total = aulas.Count(c => c.NomeAula.Contains("Engenharia"));
Ler

6 de agosto de 2020

Transferência de dados CLOB entre bancos Oracle, via DB Link




Uma vez, ao implementar um programa que precisava comunicar dois bancos de dados Oracle 11g diferentes, e em tempo real, uma limitação do próprio banco de dados em enviar de dados CLOB de um banco para o outro via DB link tornou-se um grande problema. Caso este problema não fosse contornado de alguma maneira, não seria possível fazer a integração entre os bancos em tempo real. Como esta limitação está relacionada ao tamanho que os dados CLOB comportam, a solução foi dividir as informações a serem transferidas em blocos informações menores e em um tipo de dado que permitisse a transferência das informações entre os bancos de dados, neste caso, o VARCHAR2.

Mas o que é um DB Link?
Conforme a documentação fornecida pela Oracle, um DB Link é um objeto de esquema que permite o acesso aos objetos à partir de outro banco de dados.
Após a criação do link, é possível acessar os objetos do outro banco através de instruções SQL, adicionando "@nomedblink" logo após o nome do objeto. Também é possível executar outras instruções SQL, como por exemplo INSERT, UPDATE, DELETE, LOCK TABLE.

Por sorte, a própria Oracle já fornece algumas funções para a manipulação de dados de tipo "LOB" (Large Objects). Estas funções se encontram dentro do pacote "dbms_lob".

Para a solução deste problema foram usadas apenas 4 funções, que são:

Função "dbms_lob.substr"
Utilizada para ler um tipo de dado CLOB, NCLOB ou BLOB à partir de um offset ("deslocamento").
"[…] É uma função passada-por-valor que retorna um tipo de dados RAW para tipos BFILE e BLOB e VARCHAR2 para CLOB ou NCLOB. [...]" (MCLAUGHLIN, 2009, p.311).
Em outras palavras, com esta função é possível retornar um pedaço de um texto armazenado dentro de um campo CLOB, por exemplo.

Função "dbms_lob.createtemporary"
Cria um BLOB, CLOB ou NCLOB temporário na memória. "[…] Os LOBs temporários são entidades de limite de tempo[...]" (MCLAUGHLIN, 2009, p.313), ou seja, somem da memória assim que o processo é finalizado (ou assim que são explicitamente "destruídos").

Função "dbms_lob.append"
É utilizado para adicionar conteúdos ao final de um LOB. (MCLAUGHLIN, 2009, p.304).

Função "dbms_lob.freetemporary"
É utilizado para liberar a memória consumida por um BLOB, CLOB ou NCLOB criado através da função "dbms_lob.createtemporary". Recomenda-se que esta função sempre deva ser utilizada ao trabalhar com LOBs temporários. (MCLAUGHLIN, 2009, p.313).

Implementação

Para o desenvolvimento deste exemplo fez-se uso do banco Oracle 11g Express Edition, por ser uma versão gratuita.
A título de exemplificação, foram criados 2 usuários. "user_emissor" e "user_externo". O usuário "user_emissor" representará o banco de dados que contém a origem das informações, ou seja, que contém a tabela com uma coluna do tipo de dado CLOB. Já o usuário "user_externo" representará um banco de dados externo que precisa fazer o acesso ao banco proprietário das informações ("user_emissor").
Para que a comunicação entre os usuário seja possível, é necessária a criação de pelo menos 2 objetos. Sendo um pacote que fará a serialização do CLOB num vetor de VARCHAR2 no usuário "user_emissor", e uma função que concatenará o vetor novamente em CLOB no usuário "user_externo". No exemplo também será criada uma view no usuário "user_externo". A implementação desta view não é obrigatória, mas facilitará a exibição dos dados.

Estrutura da tabela "exemplo_clob":
Dentro do esquema do usuário "user_emissor" existe a tabela "exemplo_clob".

Diagrama Tabela "exemplo_clob".

Esta é a tabela que precisa ser acessada pelo usuário "user_externo".
Ela possui apenas duas colunas, sendo uma para a identificação de seus registros ("id_exemplo_clob"), e outra coluna ("texto") que armazena as informações que precisam ser lidas pelo usuário "usuario_externo".


Pacote "PKG_LOB"

Para que a integração entre os bancos de dados seja possível, é necessária a implementação de um pacote que contenha a definição de um objeto do tipo TABLE. É através deste pacote que o usuário "user_externo" irá ter acesso à estrutura de dados em que o CLOB foi serializado.

Estrutura do pacote "pkg_lob". É através dela que o usuário "user_externo" terá acesso às informações do CLOB serializado.


A figura acima tem um exemplo da definição do pacote, e abaixo o detalhamento desta estrutura:
A linha 1 corresponde à instrução de criação do pacote
A linha 2 marca o início das definições do pacote. É a partir dela que todos os objetos e procedimento são definidos. Todos os objetos e procedimento públicos, ou seja, que podem ser acessados por outros objetos/usuário, devem estar descritos neste bloco.
Na linha 4 está a declaração de uma estrutura de dados do tipo TABLE OF VARCHAR2(4000). É a partir desta estrutura que os objetos de manipulação do CLOB serão montados. O tamanho do VARCHAR2 é de 4000, pois é o limite que uma instrução SELECT pode manipular.
Nas linhas 8 à 10 tem-se a definição da função que irá fazer a serialização do CLOB num vetor de VARCHAR2. Entre elas, na linha 9, está a declaração de um parâmetro de entrada que será utilizado para filtrar a informação desejada. Deve-se atentar à linha 10, pois ela define o retorno da função como sendo a estrutura de dados criada anteriomente.
Por fim, a linha 12 marca o final da declaração do pacote.


Corpo do pacote

Estrutura do corpo do pacote "pkg_lob". Contém o algoritmo que faz a serialização do CLOB num vetor VARHCAR2.

O corpo do pacote é onde está contida toda a lógica (figura acima). Abaixo segue o detalhamento de sua estrutura:

A linha 1 corresponde à instrução de criação do corpo do pacote.
A linha 2 marca o início das declarações de todos os objetos e procedimentos acessíveis dentro do pacote. Nenhum objeto e/ou procedimento que esteja dentro desta declaração será público, exceto para os casos dos procedimentos estejam declarados na estrutura do pacote que permite o acesso externo.
Entre as linhas 6 e 38 está a função responsável por fazer a serialização do CLOB no array de VARCHAR2.
As linhas 6 a 8 criam a definição da função. Esta deve estar exatamente igual ao que foi definido na estrutura principal do pacote.
Entre as linhas 9 e 11 está a declaração da variável "v_array" do tipo TabArray, onde TabArray é o objeto TYPE criado na definição do pacote, e a declaração de uma constante ("c_max_length"), que armazena o valor máximo de cada bloco VARCHAR2 do vetor.
A linha 14 faz a inicialização do objeto vetor.
Na linha 17 está a declaração do loop que fará a serialização do CLOB em VARCHAR2.
Entre as linhas 18 e 24 estão as instruções SELECT que fazem a serialização do CLOB em VARCHAR2. Para que seja possível o entendimento desta instrução, precisa-se olhar do SELECT interno para o SELECT externo. O SELECT interno faz uso da função CEIL com a função LENGTH (linha 20). A função LENGTH faz a contagem da quantidade de caracteres contidos no CLOB. Este resultado é divido pela constante "c_max_length", que é o limite de caracteres definido para este exemplo. Ao resultado desta divisão é aplicada a função CEIL. Esta função faz com que um valor que contenha casas decimais seja arredondado para o próximo valor inteiro. Exemplo: CEIL(4,01) = 5. A este resultado da-se o alias (apelido) de "qtd_linhas"
Logo abaixo, na linha 21, o SELECT retorna a coluna "texto", que é a coluna que contém o(s) valor(es) CLOB(s) a ser(em) serializado(s).
Na linha 23 o parâmetro "pi_id_exemplo_clob" é utilizado para filtrar apenas um registro da tabela e fazer a serialização das informações deste registro.
Com base nas informações retornada pelo SELECT interno, o SELECT externo faz a serialização dos dados CLOB através da combinação da clausula CONNECT BY com a função "dbms_lob.substr". Ao utilizar a cláusula CONNECT BY com o resultado de "qtd_linhas" faz-se com que o SELECT retorne uma quantidade de linhas igual ao valor de "qtd_linhas", ou seja, se "qtd_linhas" for igual a 7, o SELECT retornará 7 linhas, por exemplo. O identificador de cada linha fica por conta da função "LEVEL", que retorna qual é a posição de cada linha na hierarquia.
O resultado de "LEVEL" possui 2 utilidades, definir o índice das posições do vetor (linha 19), e, junto da função "dbms_lob.subtr", realizar a divisão do CLOB em blocos de VARCHAR2 (linha 21).
As linhas 25 e 33 marcam, respectivamente, o início e o fim do bloco que carrega o vetor.
A linha 28 cria, através da função "EXTEND", uma nova posição para o vetor "v_array".
A linha 31 define o índice de "v_array" com o valor de "LEVEL" (ao qual foi dado alias de "i") e atribui na posição deste índice o bloco de VARCHAR2 gerado pelo SELECT.
Ao finalizar todas as iterações do loop, o vetor "v_array" é retornado através da instrução "RETURN" (linha 37).
A linha 38 marca o final da função, e a linha 44 marca o final da declaração do corpo do pacote.

Partimos agora para a função "get_exemplo_clob_texto". É através dela que a desserialização do CLOB é feita. Ela também é responsável por criar o vínculo entre os usuários "user_externo" e "user_emissor".

Estrutura da função "get_exemplo_clob_texto". É responsável por fazer a desserialização do vetor e retornar um CLOB.


As linhas 1 e 3 marcam definição da função, que é igual à função que está dentro do pacote "pkg_lob" no usuário "user_emissor", exceto pelo tipo de dado a ser retornado, que, neste caso, é um CLOB.
Entre as linhas 5 e 7 estão declaradas 3 variáveis. Uma do tipo TabArray ("v_array") e duas do tipo CLOB ("v_temp" e "v_texto"). É importante perceber que a declaração da variável "v_array" é feita com o uso do DB link, fazendo referência ao objeto TabArray do pacote "pkg_lob", que pertence ao usuário "user_emissor". É aqui onde encontra-se todo o segredo por trás do algoritmo, pois a estrutura que é utilizada para criar o vetor passa a ser compartilhado por ambos os usuários.
Entre as linhas 12 e 14 está a chamada para a função "pkg_lob.get_exemplo_clob_texto" e armazena o valor que ela retorna dentro da variável "v_array".
Após isso, na linha 17, um objeto temporário do tipo CLOB é criado através da variável "v_temp" e a função "dbms_lob.createtemporary".
O bloco entre as linhas 20 e 22 é responsável por varrer todo o vetor, e concatenar os dados contidos dentro de cada um dos blocos deste vetor na variável "v_temp", através da função "dbms_lob.append".
Após este processamento, o resultado obtido em "v_temp" é atribuído à variável "v_texto" (linha 25), e, logo em seguida, a variável temporária "v_temp" é eliminada da memória com o uso da função "dbms_lob.freetemporary" (linha 28).
Por fim, na linha 31, a função devolve os dados que foram inicialmente recebidos de maneira serializada, como se fosse originalmente um dado do tipo CLOB.
A linha 33 marca o final de todo o bloco correspondente à função.


Visualização dos dados através da view "VIEW_EXEMPLO_CLOB"

A estrutura da view é feita de maneira que de a impressão ao usuário que ela nada mais é que um "espelho" da tabela "exemplo_clob". Assim como a função "get_exemplo_clob_texto", ela também é implementada no lado do usuário "user_externo".

Estrutura da view "view_exemplo_clob". Criada para facilitar o acesso às informações da tabela "exemplo_clob" do usuário "user_emissor".

Abaixo segue o detalhamento de sua estrutura:
A primeira linha é onde defíne-se o nome da view.
A linha 2 marca o ponto à partir de onde será criado a instrução da consulta.
Entre as linhas 3 e 5 está a instrução da consulta utilizada para retornar os dados. Na linha 3 para o ínico da consulta através da cláusula "SELECT". Junto da instrução "SELECT" está a coluna "id_exemplo_clob" da tabela "exemplo_clob". A linha 4 faz uso da função "get_exemplo_clob_texto" e informa o "id_exemplo_clob" como parâmetro da função. Isso significa que será buscado o texto correspondente à identificação da linha que está sendo processada. Por fim, na linha 5 está identificada a fonte dos dados, ou seja, a tabela "exemplo_clob". Como esta tabela não pertence ao usuário "user_externo", faz-se necessário o uso do DB link para que as informações sejam acessdas.
A linha 6 marca o final do script de criação da view.

Comparando os resultados

A fim de mostrar a eficácia deste método, duas consultas exatamente iguais são executadas, uma para cada um dos usuários. Exceto que para o usuário "user_emissor" a consulta será em cima da tabela "exemplo_clob", enquanto no usuário "user_externo" a consulta é em cima da view "view_exemplo_clob". Porém isto não afeta o resultado, uma vez que a fonte de dados da view é a tabela "exempl_clob", ou seja, extamente a mesma fonte de dados utilizada para o usuário "user_emissor".

Execução da consulta no usuário "user_emissor":

Consulta no usuário "user_emissor"

Execução da consulta no usuário "user_externo":

Consulta no usuário "user_externo".


Como uma coluna CLOB pode armazenar um valor muito grande (e que talvez não seja possível visualizar por completo, como é o caso deste exemplo), a função "LENGHT" foi utilizada para realizar a comparação do tamanho do texto retornado em cada usuário. Como podemos observar, o resultado para ambos os usuários foi exetamente igual, "18346" caracteres. Isso mostra que toda a serialização e desserialização destes dados ocorreu como o esperado, uma vez que nenhuma informação foi perdida, ou acressida.

Referências

WATSON, John; RAMKLASS, Roopesh. OCA Oracle Database 11g: Fundamentos I SQL. Rio de Janeiro: Alta Books, 2008. 564 p.

MCLAUGHLIN, Michael. Oracle Database 11g: PL/SQL Programação. Rio de Janeiro: Alta Books, 2009. 830 p.

ORACLE. CREATE DATABASE LINK. 2005. Disponível em: <https://docs.oracle.com/cd/B19306_01/server.102/b14200/statements_5005.htm>. Acesso em: 15 abr. 2017.

ORACLE. HIERARCHICAL QUERIES 2005. Disponível em: <https://docs.oracle.com/cd/B19306_01/server.102/b14200/queries003.htm>. Acesso em: 18 mai. 2017.

ORACLE. HIERARCHICAL QUERIES PSEUDOCOLUMNS 2005. Disponível em: <https://docs.oracle.com/cd/B19306_01/server.102/b14200/pseudocolumns001.htm#i1009261>. Acesso em: 18 mai. 2017.

ORACLE. DBMS_LOB 2005. Disponível em: <http://docs.oracle.com/cd/B19306_01/appdev.102/b14258/d_lob.htm>. Acesso em: 18 mai. 2017.
Ler