<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Dev Iniciante]]></title><description><![CDATA[Dev Iniciante]]></description><link>https://www.codigobasico.com.br</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1753476560230/17d009c3-a468-4326-aea7-23058a5f4360.png</url><title>Dev Iniciante</title><link>https://www.codigobasico.com.br</link></image><generator>RSS for Node</generator><lastBuildDate>Thu, 23 Apr 2026 08:34:19 GMT</lastBuildDate><atom:link href="https://www.codigobasico.com.br/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Construindo uma API REST em .NET com Oracle XE e Stored Procedures [Parte 3].]]></title><description><![CDATA[Nesta terceira parte, daremos continuidade a construção da nossa API REST em .NET Core com Oracle XE e Stored Procedures.
Camada Controller: o ponto de entrada da API
A camada Controller em uma aplicação ASP.NET Core representa o ponto de entrada das...]]></description><link>https://www.codigobasico.com.br/construindo-uma-api-rest-em-net-com-oracle-xe-e-stored-procedures-parte-3</link><guid isPermaLink="true">https://www.codigobasico.com.br/construindo-uma-api-rest-em-net-com-oracle-xe-e-stored-procedures-parte-3</guid><category><![CDATA[dotnet]]></category><category><![CDATA[Aspnetcore]]></category><category><![CDATA[Oracle]]></category><category><![CDATA[Web API]]></category><category><![CDATA[REST API]]></category><category><![CDATA[dependency injection]]></category><dc:creator><![CDATA[Flavio dos Santos]]></dc:creator><pubDate>Mon, 28 Jul 2025 20:51:58 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1753735610070/91ec37b5-ac88-4852-88a7-9e4e0e8fed04.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Nesta terceira parte, daremos continuidade a construção da nossa API REST em .NET Core com Oracle XE e Stored Procedures.</p>
<h2 id="heading-camada-controller-o-ponto-de-entrada-da-api">Camada Controller: o ponto de entrada da API</h2>
<p>A camada <strong>Controller</strong> em uma aplicação <strong>ASP.NET Core</strong> representa o ponto de entrada das requisições <strong>HTTP</strong>. Ela é responsável por receber, interpretar e encaminhar as chamadas realizadas pelo cliente, como navegadores, aplicativos móveis ou ferramentas de integração, para o serviços apropriados da aplicação. Os <strong>controllers</strong> devem ser simples e diretos, delegando toda a lógica de negócio a camada de serviços (<strong>Application</strong>). Essa separação de responsabilidades mantém o código limpo, testável e aderente aos princípios da arquitetura em camadas. Além disso, cada método do <strong>controller</strong> é geralmente associado a uma rota e um verbo <strong>HTTP</strong>(<strong>GET</strong>, <strong>POST</strong>, <strong>PUT</strong>, <strong>DELETE</strong>), formando os chamados endpoints <strong>RESTful</strong>.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text"><strong>Observação</strong>: Embora existam projetos onde os desenvolvedores optam por realizar validações diretamente nas controllers (como verificar se o modelo está bem formado com ModelState.IsValid), é importante tomar cuidado para que essas validações permaneçam simples e estruturais. Regras de negócio, como verificar se um e-mail já está cadastrado ou se o usuário tem permissão para determinada ação, devem sempre ser delegadas à camada de aplicação. Isso evita violar o princípio da responsabilidade única e mantém a arquitetura coesa e sustentável.</div>
</div>

<h3 id="heading-implementando-a-usercontroller-expondo-os-endpoints-da-api">Implementando a UserController: expondo os endpoints da API</h3>
<p>A classe <code>UserController</code> é responsável por expor os endpoints <strong>HTTP</strong> da nossa <strong>API REST</strong>, funcionando como o ponto de entrada das operações relacionadas a usuários. Cada método corresponde a uma ação do <em>CRUD</em>, utilizando os <em>verbos HTTP</em> apropriados (<code>GET</code>, <code>POST</code>, <code>PUT</code>, <code>DELETE</code>) e delegando as operações à camada de serviço (<code>IUserService</code>). Essa estrutura mantém o <em>controller</em> enxuto e focado apenas em receber requisições, validar a estrutura dos dados e retornar respostas <em>HTTP</em> padronizadas. A lógica de negócio permanece encapsulada no serviço, garantindo separação de responsabilidade e alinhamento com os princípios da arquitetura em camadas.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> Microsoft.AspNetCore.Mvc;
<span class="hljs-keyword">using</span> OracleCrud.Sp.Api.Application.Interfaces;
<span class="hljs-keyword">using</span> OracleCrud.Sp.Api.Domain.Dtos;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">OracleCrud.Sp.Api.Controllers</span>;

[<span class="hljs-meta">ApiController</span>]
[<span class="hljs-meta">Route(<span class="hljs-meta-string">"api/[controller]"</span>)</span>]
<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">UserController</span> : <span class="hljs-title">ControllerBase</span>
{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> IUserService _userService;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">UserController</span>(<span class="hljs-params">IUserService userService</span>)</span>
    {
        _userService = userService;
    }

    [<span class="hljs-meta">HttpGet</span>]
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task&lt;ActionResult&lt;IEnumerable&lt;UserDto&gt;&gt;&gt; GetAll()
    {
        <span class="hljs-keyword">var</span> users = <span class="hljs-keyword">await</span> _userService.GetAllAsync();
        <span class="hljs-keyword">return</span> Ok(users);
    }

    [<span class="hljs-meta">HttpPost</span>]
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task&lt;ActionResult&lt;<span class="hljs-keyword">string</span>&gt;&gt; Insert([FromBody] CreateUserDto user)
    {
        <span class="hljs-keyword">if</span> (!ModelState.IsValid)
            <span class="hljs-keyword">return</span> BadRequest(ModelState);

        <span class="hljs-keyword">var</span> result = <span class="hljs-keyword">await</span> _userService.InsertAsync(user);
        <span class="hljs-keyword">return</span> Ok(result);
    }

    [<span class="hljs-meta">HttpPut</span>]
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task&lt;ActionResult&lt;<span class="hljs-keyword">string</span>&gt;&gt; Update([FromBody] UserDto user)
    {
        <span class="hljs-keyword">if</span> (!ModelState.IsValid)
            <span class="hljs-keyword">return</span> BadRequest(ModelState);

        <span class="hljs-keyword">var</span> result = <span class="hljs-keyword">await</span> _userService.UpdateAsync(user);
        <span class="hljs-keyword">return</span> Ok(result);
    }

    [<span class="hljs-meta">HttpDelete(<span class="hljs-meta-string">"{id}"</span>)</span>]
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task&lt;ActionResult&lt;<span class="hljs-keyword">string</span>&gt;&gt; Delete(<span class="hljs-keyword">string</span> id)
    {
        <span class="hljs-keyword">var</span> result = <span class="hljs-keyword">await</span> _userService.DeleteAsync(id);
        <span class="hljs-keyword">return</span> Ok(result);
    }
}
</code></pre>
<h2 id="heading-programcs-configurando-o-pipeline-e-a-injecao-de-dependencias">Program.cs: configurando o pipeline e a injeção de dependências</h2>
<p>O arquivo <code>Program.cs</code> é o ponto de entrada da aplicação <strong>ASP.NET Core</strong>. Nele configuramos o pipeline de execução da aplicação, os serviços que serão injetados via dependência e os middlewares que vão atuar nas <em>requisições HTTP</em>. É nesse local que registramos o <code>IUserService</code> e o <code>IUserRepository</code> para que o <strong>ASP.NET Core</strong> saiba como instanciar essas dependências sempre que forem solicitadas, por exemplo, dentro da <code>UserController</code>. Também configuramos o <strong>Swagger</strong>, que facilita o teste manual da API, e definimos o ambiente da aplicação. Essa organização centralizada torna o ciclo de vida da aplicação mais transparente e controlado, seguindo boas práticas modernas de desenvolvimento com .NET.</p>
<h3 id="heading-injecao-de-dependencia-conectando-interfaces-e-implementacoes">Injeção de Dependência: conectando interfaces e implementações</h3>
<p>No Program.cs, realizamos o registro das interfaces <code>IUserService</code> e <code>IUserRepository</code> com suas respectivas implementações <code>UserService</code> e <code>UserRepository</code> utilizando o método <code>AddScoped</code>. Essa abordagem segue o padrão de injeção de dependência nativo do ASP.NET Core, permitindo que o framework forneça automaticamente as instâncias, como nos <em>controllers</em>. O uso do <code>Scoped</code> garante que uma nova instância será criada por requisição HTTP, o que é ideal para serviços que acessam o banco de dados. Essa prática promove desacoplamento, facilidade de testes e clareza na manutenção, sendo um dos pilares da arquitetura limpa adotada no projeto.</p>
<pre><code class="lang-csharp">builder.Services.AddControllers();

builder.Services.AddScoped&lt;IUserService, UserService&gt;();
builder.Services.AddScoped&lt;IUserRepository, UserRepository&gt;();
</code></pre>
<h2 id="heading-testando-o-endpoint-get-apiuser-no-postman">Testando o endpoint GET /api/User no Postman</h2>
<p>Ao executar o projeto em ambiente de desenvolvimento, o ASP.NET Core gera automaticamente uma URL com porta dinâmica, neste caso <code>http://localhost:5219</code>, conforme definido no <code>launchSettings.json</code>. É importante destacar que, no seu ambiente, essa porta pode ser diferente, como <code>5000</code>, ou <code>7048</code>, dependendo da configuração ou do que o Visual Studio ou SDK do .NET escolherem no momento da execução. Utilizando o <strong>Postman</strong>, realizamos uma requisição <code>GET</code> para o endpoint <code>/api/User</code>, que é responsável por listar todos os usuários cadastrados. A resposta retornou com status <strong>200 OK</strong>, indicando que o endpoint está ativo e funcional. No entanto, o corpo da resposta foi um array vazio (<code>[]</code>), o que significa que nenhum usuário está presente no banco de dados no momento, o que é um comportamento esperado em em um ambiente recém iniciado, antes de qualquer inserção</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753730845851/39e8f7d3-6f26-4e6d-a1f4-c785d2494586.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-testando-o-endpoint-post-apiuser-no-postman">Testando o endpoint POST /api/User no Postman</h2>
<p>Neste teste, utilizamos o Postman para enviar uma requisição <code>POST</code> ao endpoint <code>/api/User</code>, com o objetivo de cadastrar um novo usuário. A requisição foi feita com o corpo no formato <code>JSON</code>, contendo os campos <code>name</code> e <code>email</code>, conforme esperado pelo <strong>DTO</strong> <code>CreateUserDto</code>. O endpoint respondeu com status <code>200 OK</code> e a mensagem <strong>“Usuário inserido com sucesso.”</strong>, indicando que a operação foi executada corretamente e os dados foram persistidos no banco de dados via stored procedure. Assim como no exemplo anterior, a URL utilizada foi <code>http://localhost:5219</code>, porém é importante lembrar que essa porta pode variar de acordo com o ambiente de execução de cada desenvolvedor, conforme definido no <code>launchSettings.json</code>. Se no seu projeto a porta for diferente, isso é completamente normal e não afeta o funcionamento da API.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753732058439/1e50b7c3-0cb2-4d46-acca-98107f30fbd2.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-reexecutando-o-get-apiuser-para-consultar-o-novo-registro">Reexecutando o GET /api/User para consultar o novo registro</h2>
<p>Após a inserção bem sucedida de um novo usuário com o endpoint <code>POST /api/User</code>, realizamos novamente a requisição GET /api/User para verificar se o dado foi persistido corretamente no banco. Desta vez, o retorno trouxe uma lista contendo o objeto recém cadastrado, incluindo seu <code>id</code> gerado automaticamente, além dos campos <code>name</code> e <code>email</code>. O status <code>200 OK</code> confirma que a requisição foi processada com sucesso e que o fluxo de inserção e leitura está funcionando conforme esperado. Esse tipo de verificação é essencial para garantir a integridade dos dados e validar que o repositório está acessando corretamente a base <strong>Oracle</strong> via <strong>stored procedures</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753732624960/a3c967aa-c9c1-4234-9f93-3b5d8522cc8a.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-testando-o-endpoint-put-apiuser-para-atualizar-um-usuario">Testando o endpoint PUT /api/User para atualizar um usuário</h2>
<p>Neste teste, utilizamos o <strong>Postman</strong> para enviar uma requisição <code>PUT</code> ao endpoint <code>/api/User</code>, com o objetivo de atualizar os dados de um usuário já existente. No corpo da requisição, foi informado o <code>id</code> do usuário previamente inserido, juntamente com os novos valores para os campos <code>name</code> e <code>email</code>. A resposta retornou com status <code>200 OK</code> e a mensagem <strong>"Usuário atualizado com sucesso."</strong>, confirmando que a operação foi concluída com êxito. Isso demonstra que a comunicação com a <strong>stored procedure</strong> <code>sp_update_user</code> está funcionando corretamente e que a aplicação está atualizando registros no banco de dados conforme esperado. Lembre-se de que, se o id informado não existir, a própria procedure retorna uma mensagem apropriada, garantindo um controle confiável de validação no nível de banco.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753733651451/2938dd27-816c-464f-9312-9b8ff7dd7fe2.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-verificando-a-atualizacao-com-uma-nova-chamada-get">Verificando a atualização com uma nova chamada GET</h2>
<p>Após a requisição de atualização com sucesso, reexecutamos o endpoint GET /api/User para verificar se os dados do usuário foram realmente modificados no banco. A resposta confirmou a alteração, retornando o nome atualizado com <strong>“Flavio Update”</strong> e o nomes e-mail previamente cadastrado. Isso demonstra que o processo de persistência com stored procedure está funcionando corretamente, refletindo imediatamente as mudanças realizadas.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753733883752/64d93804-5c01-45d0-b072-cd82ab35ee35.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-testando-o-endpoint-delete-apiuser-para-remover-um-usuario">Testando o endpoint DELETE /api/User para remover um usuário</h2>
<p>Neste teste, utilizamos o <strong>Postman</strong> para enviar uma requisição <code>DELETE</code> ao endpoint <code>/api/User/{id}</code>, informando diretamente na URL o id do usuário que havia sido previamente inserido e atualizado. A resposta retornou com status <code>200 OK</code> e a mensagem <strong>"Usuário excluído com sucesso."</strong>, confirmando que a operação foi concluída corretamente. Essa resposta é gerada pela stored procedure <code>sp_delete_user</code>, que também valida se o <code>id</code> existe no banco e retorna mensagens específicas em caso de erro. Com isso, completamos o ciclo do <strong>CRUD</strong> (<strong>Create</strong>, <strong>Read</strong>, <strong>Update</strong>, <strong>Delete</strong>), validando que todas as operações estão integradas corretamente com o banco Oracle.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753734638093/68ce4645-ce4f-4a28-bb26-3caf9bfdae04.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-conclusao">Conclusão</h2>
<p>Na terceira parte da série <strong>Construindo uma API REST em .NET com Oracle XE e Stored Procedures [Parte 3]</strong>, implementamos a camada de controllers da aplicação e realizamos testes práticos dos principais endpoints do <code>CRUD</code>: <code>GET</code>, <code>POST</code>, <code>PUT</code> e <code>DELETE</code>. Exploramos como os controllers se comunicam com a camada de serviços, como configurar corretamente a injeção de dependência no Program.cs e validamos toda a integração com o <strong>banco de dados Oracle</strong> por meio de chamadas <strong>HTTP</strong> usando o <strong>Postman</strong>. Com isso, nossa API já é capaz de executar todas as operações básicas com segurança e organização. Na <strong>Parte 4</strong>, concluiremos a aplicação com um resumo geral do que construímos até aqui, consolidando o aprendizado e reforçando os principais conceitos abordados ao longo da série.</p>
]]></content:encoded></item><item><title><![CDATA[Construindo uma API REST em .NET com Oracle XE e Stored Procedures [Parte 2].]]></title><description><![CDATA[Nesta segunda parte, daremos continuidade à construção da nossa API REST em .NET com Oracle XE e Stored Procedures.
A camada Application e sua função na organização da Regra de Negócio
A Camada Application é responsável por orquestrar a lógica da apl...]]></description><link>https://www.codigobasico.com.br/construindo-uma-api-rest-em-net-com-oracle-xe-e-stored-procedures-parte-2</link><guid isPermaLink="true">https://www.codigobasico.com.br/construindo-uma-api-rest-em-net-com-oracle-xe-e-stored-procedures-parte-2</guid><category><![CDATA[dotnetcore]]></category><category><![CDATA[Oracle]]></category><category><![CDATA[Clean Architecture]]></category><category><![CDATA[APIs]]></category><category><![CDATA[backend]]></category><dc:creator><![CDATA[Flavio dos Santos]]></dc:creator><pubDate>Fri, 25 Jul 2025 14:59:36 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1753454932711/0ce59535-ba36-4ed2-a9a6-759f55c60e49.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Nesta segunda parte, daremos continuidade à construção da nossa <em>API REST em .NET com Oracle XE e Stored Procedures</em>.</p>
<h2 id="heading-a-camada-application-e-sua-funcao-na-organizacao-da-regra-de-negocio">A camada Application e sua função na organização da Regra de Negócio</h2>
<p>A Camada <strong>Application</strong> é responsável por orquestrar a lógica da aplicação, fazendo a ponte entre os controladores e a infraestrutura. É aqui que centralizamos as interfaces e sua implementações concretas, como a <code>UserService</code>, que aplica regras básicas e delega persistência ao <code>IUserRepository</code>, sem depender diretamente do banco de dados.</p>
<p>Seguimos os princípios da Clean Architecture, mantendo a separação de responsabilidade e favorecendo testabilidade e desacoplamento. Embora a <strong>Application</strong> esteja organizada como uma pasta dentro do projeto principal, ela poderia facilmente ser movida para uma <strong>class library</strong> separada, o que é comum em aplicações maiores.</p>
<p>Vale ressaltar que, embora tenhamos optado por uma estrutura mais enxuta e direta, sem o uso de padrões como <strong>Command Handlers</strong>, <strong>Use Cases</strong> explícitos ou <strong>Value Objects</strong>, esse modelo é comum em muitos projetos reais e funciona bem em contextos onde a complexidade do domínio é moderada. A escolha visa manter o foco nos fundamentos, com uma organização clara, de fácil leitura e alinhada aos princípios modernos da arquitetura em camadas.</p>
<h2 id="heading-implementando-a-classe-userservice">Implementando a Classe UserService</h2>
<p>Com a estrutura da camada <strong>Application</strong> definida, seguimos para a implementação da classe <code>UserService</code>, que é a implementação concreta da interface <code>IUserService</code>, e tem como responsabilidade orquestrar as operações relacionadas a usuários. Ela atua como intermediária entre o controlador e o repositório, garantindo que a lógica de negócio permaneça desacoplada da infraestrutura.</p>
<p>Ao receber um <code>CreateUserDto</code>, a <code>UserService</code> utiliza a biblioteca <strong>Flavio.Santos.NetCore.ObjectMapping</strong> para convertê-lo em um <code>UserDto</code>, e adiciona um <code>Id</code> gerado com <code>Guid.NewGuid()</code>. Esse processo mantém o código limpo e evita duplicação. Em seguida, a instância convertida é repassada para o repositório via <code>IUserRepository</code>, que realiza a persistência no banco.</p>
<p>Os métodos <code>GetAllAsync()</code>, <code>UpdateAsync()</code> e <code>DeleteAsync()</code> seguem o mesmo padrão: aplicam regras simples, quando necessário, e delegam as ações ao repositório. Essa abordagem reforça a separação de responsabilidade e contribui para uma arquitetura modular, mantendo a aplicação mais organizada, testável e alinhada aos princípios da <strong>Clean Architecture</strong>.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> OracleCrud.Sp.Api.Application.Interfaces;
<span class="hljs-keyword">using</span> OracleCrud.Sp.Api.Domain.Dtos;
<span class="hljs-keyword">using</span> FDS.NetCore.ObjectMapping.Extensions;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">OracleCrud.Sp.Api.Application.Services</span>;

<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">UserService</span> : <span class="hljs-title">IUserService</span>
{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> IUserRepository _repository;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">UserService</span>(<span class="hljs-params">IUserRepository repository</span>)</span>
    {
        _repository = repository;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task&lt;IEnumerable&lt;UserDto&gt;&gt; GetAllAsync()
    {
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> _repository.GetAllAsync();
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task&lt;<span class="hljs-keyword">string</span>&gt; <span class="hljs-title">InsertAsync</span>(<span class="hljs-params">CreateUserDto user</span>)</span>
    {
        <span class="hljs-keyword">var</span> userDto = user
            .MapTo&lt;UserDto&gt;()
            .Apply(t =&gt; t.Id = Guid.NewGuid().ToString());

        <span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> _repository.InsertAsync(userDto);
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task&lt;<span class="hljs-keyword">string</span>&gt; <span class="hljs-title">UpdateAsync</span>(<span class="hljs-params">UserDto user</span>)</span>
    {
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> _repository.UpdateAsync(user);
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task&lt;<span class="hljs-keyword">string</span>&gt; <span class="hljs-title">DeleteAsync</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> id</span>)</span>
    {
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> _repository.DeleteAsync(id);
    }
}
</code></pre>
<h2 id="heading-instalando-e-utilizando-a-biblioteca-flaviosantosnetcoreobjectmapping">Instalando e utilizando a biblioteca <code>Flavio.Santos.NetCore.ObjectMapping</code></h2>
<p>Para facilitar o mapeamento entre objetos com estrutura semelhante, utilizamos a biblioteca <code>Flavio.Santos.NetCore.ObjectMapping</code>. Ela oferece uma abordagem fluente, simples e sem configuração para converter objetos entre tipos diferentes com propriedades compatíveis, como no caso de <code>CreateUserDto</code> para <code>UserDto</code>.</p>
<p>A instalação pode ser feita diretamente via terminal do projeto:</p>
<pre><code class="lang-bash">dotnet add package Flavio.Santos.NetCore.ObjectMapping
</code></pre>
<p>Ou se preferir, pelo gerenciador de pacotes do <strong>Visual Studio</strong> <strong>Manage Nuget Packages</strong>.</p>
<h2 id="heading-exemplo-pratico-de-uso-da-biblioteca-de-mapeamento">Exemplo prático de uso da biblioteca de mapeamento</h2>
<p>Para compreender melhor como a biblioteca <strong>Flavio.Santos.NetCore.ObjectMapping</strong> facilita a transformação de objetos, vejamos o seguinte cenário comum: ao receber dados de um cliente via API, é comum utilizar um <strong>DTO</strong> de entrada (<code>CreateUserDto</code>). Esse objeto, então, precisa ser transformado em um <strong>DTO</strong> interno ou persistido, como o <code>UserDto</code>.</p>
<p><strong>Estrutura dos objetos:</strong></p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Objeto recebido via requisição HTTP</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">CreateUserDto</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Name { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; } = <span class="hljs-keyword">default</span>!;
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Email { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; } = <span class="hljs-keyword">default</span>!;
}

<span class="hljs-comment">// Objeto utilizado internamente ou para persistência</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">UserDto</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Id { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; } = <span class="hljs-keyword">default</span>!;
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Name { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; } = <span class="hljs-keyword">default</span>!;
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Email { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; } = <span class="hljs-keyword">default</span>!;
}
</code></pre>
<p><strong>Transformação usando MapTo() e Apply():</strong></p>
<pre><code class="lang-csharp">CreateUserDto user = <span class="hljs-keyword">new</span> CreateUserDto
{
    Name = <span class="hljs-string">"João"</span>,
    Email = <span class="hljs-string">"joao@email.com"</span>
};

<span class="hljs-keyword">var</span> userDto = user
    .MapTo&lt;UserDto&gt;()
    .Apply(u =&gt; u.Id = Guid.NewGuid().ToString());
</code></pre>
<p>Neste exemplo:</p>
<ul>
<li><p>O método <code>MapTo&lt;UserDto&gt;()</code> copia automaticamente as propriedades com nomes e tipos compatíveis (<code>Name</code> e <code>Email</code>).</p>
</li>
<li><p>O método <code>Apply(…)</code> adiciona o valor <code>Id</code>, permitindo estender o objeto de maneira fluente, sem criar código repetitivo.</p>
</li>
</ul>
<p>Esse tipo de abordagem é especialmente útil em serviços de aplicação e camadas intermediárias, reduzindo o acoplamento e aumentando a clareza do código.</p>
<h2 id="heading-a-camada-infrastructure-e-seu-papel-na-arquitetura">A camada Infrastructure e seu Papel na Arquitetura</h2>
<p>A camada <strong>Infrastructure</strong> é responsável por implementar os detalhes técnicos da aplicação, como o acesso ao banco de dados, chamadas externas, serviços de terceiros ou qualquer outra dependência que envolva infraestrutura. No nosso caso, ela abriga a implementação concreta da interface <code>IUserRepository</code>, utilizando a biblioteca <strong>Oracle.ManagedDataAccess.Client</strong> para executar a stored procedures no banco de dados <strong>Oracle XE</strong>. Essa separação permite que o restante da aplicação (como os serviços e controladores) dependa apenas de contratos (interfaces), mantendo o sistema mais flexível, testável e aderente ao princípio da inversão de dependência. Em projetos maiores, essa camada pode ser estruturada como uma <strong>class library</strong> separada, reforçando o desacoplamento entre regras de negócio e detalhes de infraestrutura.</p>
<h2 id="heading-implementando-a-classe-userrepository">Implementando a Classe UserRepository</h2>
<p>A classe <code>UserRepository</code> é responsável por concretizar o contrato definido pela interface <code>IUserRepository</code>, realizando o acesso direto ao banco de dados <strong>Oracle</strong>. Esta implementação reside na camada <strong>Infrastructure</strong>, que tem como função lidar com aspectos externos à aplicação, como persistência de dados, acesso a serviços de terceiros ou recursos do sistema.</p>
<p>Neste projeto, optamos por utilizar a biblioteca <strong>Oracle.ManagedDataAccess.Client</strong> em vez de <strong>ORMs</strong> como <strong>Entity Framework</strong> ou <strong>Dapper</strong>. Essa abordagem proporciona maior controle sobre a execução de <strong>comandos</strong> <strong>SQL</strong> e chamadas a <strong>Stored Procedures</strong>, sendo particularmente adequada quando se deseja os recursos específicos do <strong>Oracle</strong> ou seguir diretrizes de legado da empresa.</p>
<p>A classe encapsula operações como <code>GetAllAsync()</code>, <code>InsertAsync()</code>, <code>UpdateAsync()</code> e <code>DeleteAsync()</code>, comunicando-se com o banco por meio de <strong>views</strong> e <strong>procedures</strong> previamente definidas. O uso de comandos parametrizados garante segurança contra <strong>SQL Injection</strong>, além de promover clareza e previsibilidade no comportamento do repositório.</p>
<p>É importante observar que o <code>UserRepository</code> permanece completamente desacoplado da lógica de aplicação e de transformação de dados, sendo consumido exclusivamente pela <code>UserService</code>. Essa separação de responsabilidade está alinhada com os princípios da <strong>Clean Architecture</strong>, ainda que de forma simplificada e pragmática neste projeto.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> Oracle.ManagedDataAccess.Client;
<span class="hljs-keyword">using</span> OracleCrud.Sp.Api.Application.Interfaces;
<span class="hljs-keyword">using</span> OracleCrud.Sp.Api.Domain.Dtos;
<span class="hljs-keyword">using</span> System.Data;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">OracleCrud.Sp.Api.Infrastructure.Repositories</span>;

<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">UserRepository</span> : <span class="hljs-title">IUserRepository</span>
{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> <span class="hljs-keyword">string</span> _connectionString;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">UserRepository</span>(<span class="hljs-params">IConfiguration configuration</span>)</span>
    {
        _connectionString = configuration.GetConnectionString(<span class="hljs-string">"OracleDb"</span>)!;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task&lt;IEnumerable&lt;UserDto&gt;&gt; GetAllAsync()
    {
        <span class="hljs-keyword">var</span> users = <span class="hljs-keyword">new</span> List&lt;UserDto&gt;();

        <span class="hljs-keyword">using</span> <span class="hljs-keyword">var</span> connection = <span class="hljs-keyword">new</span> OracleConnection(_connectionString);
        <span class="hljs-keyword">using</span> <span class="hljs-keyword">var</span> command = <span class="hljs-keyword">new</span> OracleCommand(<span class="hljs-string">"SELECT id, name, email FROM vw_users"</span>, connection);

        <span class="hljs-keyword">await</span> connection.OpenAsync();
        <span class="hljs-keyword">using</span> <span class="hljs-keyword">var</span> reader = <span class="hljs-keyword">await</span> command.ExecuteReaderAsync();

        <span class="hljs-keyword">while</span> (<span class="hljs-keyword">await</span> reader.ReadAsync())
        {
            users.Add(<span class="hljs-keyword">new</span> UserDto
            {
                Id = reader.GetString(<span class="hljs-number">0</span>),
                Name = reader.GetString(<span class="hljs-number">1</span>),
                Email = reader.GetString(<span class="hljs-number">2</span>)
            });
        }

        <span class="hljs-keyword">return</span> users;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task&lt;<span class="hljs-keyword">string</span>&gt; <span class="hljs-title">InsertAsync</span>(<span class="hljs-params">UserDto user</span>)</span>
    {
        <span class="hljs-keyword">using</span> <span class="hljs-keyword">var</span> connection = <span class="hljs-keyword">new</span> OracleConnection(_connectionString);
        <span class="hljs-keyword">using</span> <span class="hljs-keyword">var</span> command = <span class="hljs-keyword">new</span> OracleCommand(<span class="hljs-string">"app_user.sp_insert_user"</span>, connection)
        {
            CommandType = CommandType.StoredProcedure
        };

        command.Parameters.Add(<span class="hljs-string">"p_id"</span>, OracleDbType.Varchar2).Value = user.Id;
        command.Parameters.Add(<span class="hljs-string">"p_name"</span>, OracleDbType.Varchar2).Value = user.Name;
        command.Parameters.Add(<span class="hljs-string">"p_email"</span>, OracleDbType.Varchar2).Value = user.Email;

        <span class="hljs-keyword">var</span> resultParam = <span class="hljs-keyword">new</span> OracleParameter(<span class="hljs-string">"p_result"</span>, OracleDbType.Varchar2, <span class="hljs-number">4000</span>)
        {
            Direction = ParameterDirection.Output
        };
        command.Parameters.Add(resultParam);

        <span class="hljs-keyword">await</span> connection.OpenAsync();
        <span class="hljs-keyword">await</span> command.ExecuteNonQueryAsync();

        <span class="hljs-keyword">return</span> resultParam.Value?.ToString() ?? <span class="hljs-string">"Erro ao inserir usuário."</span>;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task&lt;<span class="hljs-keyword">string</span>&gt; <span class="hljs-title">UpdateAsync</span>(<span class="hljs-params">UserDto user</span>)</span>
    {
        <span class="hljs-keyword">using</span> <span class="hljs-keyword">var</span> connection = <span class="hljs-keyword">new</span> OracleConnection(_connectionString);
        <span class="hljs-keyword">using</span> <span class="hljs-keyword">var</span> command = <span class="hljs-keyword">new</span> OracleCommand(<span class="hljs-string">"app_user.sp_update_user"</span>, connection)
        {
            CommandType = CommandType.StoredProcedure
        };

        command.Parameters.Add(<span class="hljs-string">"p_id"</span>, OracleDbType.Varchar2).Value = user.Id;
        command.Parameters.Add(<span class="hljs-string">"p_name"</span>, OracleDbType.Varchar2).Value = user.Name;
        command.Parameters.Add(<span class="hljs-string">"p_email"</span>, OracleDbType.Varchar2).Value = user.Email;

        <span class="hljs-keyword">await</span> connection.OpenAsync();
        <span class="hljs-keyword">await</span> command.ExecuteNonQueryAsync();

        <span class="hljs-keyword">return</span> <span class="hljs-string">"Usuário atualizado com sucesso."</span>;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task&lt;<span class="hljs-keyword">string</span>&gt; <span class="hljs-title">DeleteAsync</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> id</span>)</span>
    {
        <span class="hljs-keyword">using</span> <span class="hljs-keyword">var</span> connection = <span class="hljs-keyword">new</span> OracleConnection(_connectionString);
        <span class="hljs-keyword">using</span> <span class="hljs-keyword">var</span> command = <span class="hljs-keyword">new</span> OracleCommand(<span class="hljs-string">"app_user.sp_delete_user"</span>, connection)
        {
            CommandType = CommandType.StoredProcedure
        };

        command.Parameters.Add(<span class="hljs-string">"p_id"</span>, OracleDbType.Varchar2).Value = id;

        <span class="hljs-keyword">await</span> connection.OpenAsync();
        <span class="hljs-keyword">await</span> command.ExecuteNonQueryAsync();

        <span class="hljs-keyword">return</span> <span class="hljs-string">"Usuário excluído com sucesso."</span>;
    }
}
</code></pre>
<h2 id="heading-conclusao">Conclusão</h2>
<p>Concluímos nesta segunda parte da série a implementação das camadas <strong>Application</strong> e <strong>Infrastructure</strong>, elementos essenciais para estruturar a lógica de negócios e o acesso a dados de forma organizada e desacoplada. Criamos a classe <code>UserService</code>, responsável por orquestrar as operações da aplicação, e a classe <code>UserRepository</code>, que efetua a comunicação direta com o banco <strong>Oracle</strong> por meio de <strong>Stored Procedures</strong>, utilizando a biblioteca <strong>Oracle.ManagedDataAccess.Client</strong>.</p>
<p>Também introduzimos o uso da biblioteca <strong>Flavio.Santos.NetCore.ObjectMapping</strong>, que nos permitiu mapear objetos de forma simples e fluente, eliminando a necessidade de código repetitivo para transformação de <strong>DTOs</strong>.</p>
<p>Com essas camadas implementadas, a base do projeto está bem estruturada e pronta para receber a camada de apresentação.</p>
<p>Na <strong>Parte 3</strong>, vamos desenvolver os <strong>Controllers</strong>, expondo os <strong>endpoints da API</strong> e finalizando a aplicação com testes manuais <strong>via HTTP</strong>. Se você acompanhou até aqui, parabéns, estamos quase lá !!!</p>
]]></content:encoded></item><item><title><![CDATA[Construindo uma API REST em .NET com Oracle XE e Stored Procedures [Parte 1].]]></title><description><![CDATA[Justificativa para o uso dessa arquitetura
Embora as arquiteturas modernas privilegiem regras de negócio na aplicação e sigam princípios como DDD e Clean Architecture, ainda existem cenários legítimos em que Stored Procedures são utilizadas para enca...]]></description><link>https://www.codigobasico.com.br/construindo-uma-api-rest-em-net-com-oracle-xe-e-stored-procedures-parte-1</link><guid isPermaLink="true">https://www.codigobasico.com.br/construindo-uma-api-rest-em-net-com-oracle-xe-e-stored-procedures-parte-1</guid><category><![CDATA[dotnet]]></category><category><![CDATA[Web API]]></category><category><![CDATA[programming]]></category><category><![CDATA[architecture]]></category><category><![CDATA[Oracle]]></category><category><![CDATA[Stored Procedures ]]></category><category><![CDATA[backend]]></category><dc:creator><![CDATA[Flavio dos Santos]]></dc:creator><pubDate>Thu, 24 Jul 2025 12:50:27 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1753322300149/6a762fa3-1f11-4248-931e-bf09d627f6cb.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-justificativa-para-o-uso-dessa-arquitetura">Justificativa para o uso dessa arquitetura</h2>
<p>Embora as arquiteturas modernas privilegiem regras de negócio na aplicação e sigam princípios como <em>DDD</em> e <em>Clean Architecture</em>, ainda existem cenários legítimos em que Stored Procedures são utilizadas para encapsular lógica diretamente no banco de dados. Isso pode acontecer por motivos como:</p>
<p>Restrições técnicas de sistemas legados;</p>
<p>Demandas específicas de performance;</p>
<p>Políticas internas de segurança ou governança;</p>
<p>Decisões estratégicas da equipe ou da empresa.</p>
<p>Nesta série de artigos sobre a construção de uma <em>API REST com Stored Procedures</em>, o objetivo não é incentivar o uso indiscriminado dessa abordagem, mas sim mostrar como aplicá-la de forma estruturada e organizada quando ela for necessária. Em muitos projetos reais, é preciso adaptar a solução à realidade do ambiente, respeitando restrições e práticas já existentes.</p>
<h2 id="heading-criando-um-novo-projeto-no-visual-studio-2022">Criando um Novo Projeto no Visual Studio 2022</h2>
<p>Para começarmos a construção da nossa <strong>API REST</strong> com <strong>.NET 8</strong>, o primeiro passo é criar um novo projeto no <strong>Visual Studio 2022</strong>. Essa será a IDE utilizada em toda a implementação. Siga os passos abaixo para chegar até a tela de seleção de templates:</p>
<ol>
<li><p>Com o Visual Studio 2022 aberto, clique no menu <code>File &gt; New - Project</code>;</p>
</li>
<li><p>Isso abrirá uma nova janela com o título <mark>“Create a new project”</mark> ou “Add a new project” (dependendo da sua versão/idioma).</p>
</li>
<li><p>No campo de busca, digite <mark>“API”</mark> e selecione o template <mark>“ASP.NET Core Web API”</mark>;</p>
</li>
<li><p>Verifique se a linguagem está definida como <strong>C#</strong>;</p>
</li>
<li><p>Clique em <strong>Next</strong> para prosseguir com a configuração do projeto.</p>
</li>
</ol>
<p>Esta etapa define a base de nossa aplicação que será uma <strong>API REST</strong> desacoplada utilizando <strong>Stored Procedures</strong> com <strong>Oracle XE 21c</strong>.</p>
<h2 id="heading-configurando-o-nome-do-projeto">Configurando o Nome do Projeto</h2>
<p>Após selecionar o template <strong>ASP.NET Core Web API</strong>, o Visual Studio exibirá a tela <mark>“Configure your new project”</mark>. Essa etapa é responsável por definir o nome do seu projeto e o local onde ele será salvo.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753305058213/2022b854-e406-4287-9cc1-bdbb90014749.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p>Em <em>Project name</em>, insira um nome descritivo. Neste exemplo, utilizamos, <strong>OracleCrud.Sp.Api</strong>, indicando que o projeto é um CRUD com Oracle utilizando Stored Procedures;</p>
</li>
<li><p>Em <em>Location</em>, escolha a pasta onde o projeto será armazenado. No nosso caso, estamos organizando dentro da estrutura <code>src/</code> do repositório.</p>
</li>
</ul>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text"><strong>Dica</strong>: Manter os projetos dentro de uma pasta src é uma boa prática para repositórios que podem ter múltiplos projetos no futuro.</div>
</div>

<p>Após configurar, clique em <strong>Next</strong> para prosseguir com a escolha da versão do .NET.</p>
<h2 id="heading-definindo-as-configuracoes-adicionais-do-projeto">Definindo as Configurações Adicionais do Projeto</h2>
<p>Na última etapa da criação do projeto, temos a tela <mark>“Additional information”</mark>, onde configuramos detalhes importantes da nossa <strong>ASP.NET Core Web API</strong>. Veja abaixo as opções recomendadas para o nosso cenário com .<strong>NET 8</strong> e <strong>Oracle XE</strong>:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753306349860/c06431d2-ce5e-45f8-a422-e82719d148d5.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p><strong>Framework:</strong> Selecione o <code>.NET 8 (Long Term Support)</code>, que oferece suporte de longo prazo e é ideal para novos projetos.</p>
</li>
<li><p><strong>Authentication type:</strong> Marque como <code>None</code>, já que neste exemplo não implementamos autenticação.</p>
</li>
<li><p><strong>Configure for HTTPS:</strong> Mantenha marcado para garantir a segurança nas requisições.</p>
</li>
<li><p><strong>Enable OpenAPI support:</strong> Marque essa opção para que o Swagger seja configurado automaticamente, facilitando testes na API.</p>
</li>
<li><p><strong>Use controllers:</strong> Certifique-se de que está marcado, pois usaremos controllers no estilo tradicional (e não minimal APIs).</p>
</li>
</ul>
<p>Por fim, clique em <strong>Create</strong> para gerar sua <strong>API REST</strong>. Pronto! Agora temos a estrutura inicial do nosso projeto ASP.NET Core com suporte a Swagger e pronto para integrar com <strong>Oracle</strong> via <strong>Stored Procedures</strong>.</p>
<h2 id="heading-limpando-a-estrutura-inicial-do-projeto">Limpando a Estrutura Inicial do Projeto</h2>
<p>Após a criação da PAI, o Visual Studio gera alguns arquivos de exemplo que não serão utilizados no projeto. Para manter a organização e focar apenas no que é essencial, recomendamos excluir os seguites arquivos:</p>
<p>Arquivos a serem removidos:</p>
<ul>
<li><p><code>OracleCrud.Sp.Api.http</code>: Usado para testes HTTP via Visual Studio, mas será desnecessário no nosso fluxo.</p>
</li>
<li><p><code>Controllers/WeatherForecastController.cs</code>: Um controller gerado automaticamente com lógica fictícia.</p>
</li>
<li><p><code>WeatherForecast.cs</code>: Classe modelo de exemplo que não utilizaremos.</p>
</li>
</ul>
<p>Para excluir, no <strong>Solution Explorer</strong>, clique com o botão direito do mouse em cada arquivo, selecione a opção <strong>Delete</strong> e confirme a exclusão se solicitado.</p>
<h2 id="heading-separando-responsabilidades-com-dtos-distintos">Separando responsabilidades com DTOs distintos</h2>
<p>Para manter a clareza e a responsabilidade única de cada classe em nossa API, utilizamos dois <strong>Data Transfer Objects</strong> (<strong>DTOs</strong>) distintos: O <code>CreateUserDto</code> e o <code>UserDto</code>. O <code>CreateUserDto</code> é usado exclusivamente para representar os dados recebidos do frontend no momento da criação de um novo usuário. Ele não inclui o Id, pois esse campo é gerado internamente pela API ou pelo banco de dados. Já o <code>UserDto</code>, representa o objeto completo, incluindo o <code>Id</code>, e é utilizado nas respostas ou em operações internas onde o identificador já está presente. Essa separação melhora a coesão do código e facilita a manutenção e os testes da aplicação.</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// DTO recebido do Frontend (para criação de usuário)</span>
<span class="hljs-keyword">namespace</span> <span class="hljs-title">OracleCrud.Sp.Api.Domain.Dtos</span>;

<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">CreateUserDto</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Name { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; } = <span class="hljs-keyword">default</span>!;
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Email { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; } = <span class="hljs-keyword">default</span>!;
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-comment">// DTO utilizado internamente (com Id)</span>
<span class="hljs-keyword">namespace</span> <span class="hljs-title">OracleCrud.Sp.Api.Domain.Dtos</span>;

<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">UserDto</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Id { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; } = <span class="hljs-keyword">default</span>!;
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Name { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; } = <span class="hljs-keyword">default</span>!;
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Email { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; } = <span class="hljs-keyword">default</span>!;
}
</code></pre>
<h3 id="heading-por-que-os-dtos-estao-na-pasta-domain">Por que os DTOs estão na pasta Domain?</h3>
<p>Colocamos os <strong>DTOs</strong> na pasta <strong>Domain</strong> porque, nesse projeto, não estamos utilizando entidades de domínio mapeadas com <strong>ORM</strong> como o <strong>Entity Framework</strong>. Em vez disso, nossos objetos centrais de comunicação com a API(como <code>UserDto</code> e <code>CreateUserDto</code>) representam o “contrato” de dados que a aplicação conhece e manipula, sendo parte da camada de domínio. Isso reforça a ideia de que o domínio não é só composto por entidades persistidas, mas também pelos tipos que expressam regras e estruturas de negócio, mesmo que simplificadas.</p>
<h2 id="heading-definindo-contratos-com-interfaces-separando-regras-de-negocio-e-persistencia">Definindo Contratos com Interfaces: Separando Regras de Negócio e Persistência</h2>
<p>Na estrutura desta API, criamos duas interfaces fundamentais para garantir a separação de responsabilidade <code>IUserService</code> e <code>IUserRepository</code>. A <code>IUserService</code> representa o contrato da camada de serviço, responsável por orquestrar as regras de negócio da aplicação. Já a <code>IUserRepository</code> define o contrato da camada de persistência de dados, isolando a forma como acessamos o Oracle Database através de stored procedures.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> OracleCrud.Sp.Api.Domain.Dtos;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">OracleCrud.Sp.Api.Application.Interfaces</span>;

<span class="hljs-keyword">public</span> <span class="hljs-keyword">interface</span> <span class="hljs-title">IUserService</span>
{
    Task&lt;IEnumerable&lt;UserDto&gt;&gt; GetAllAsync();
    <span class="hljs-function">Task&lt;<span class="hljs-keyword">string</span>&gt; <span class="hljs-title">InsertAsync</span>(<span class="hljs-params">CreateUserDto user</span>)</span>;
    <span class="hljs-function">Task&lt;<span class="hljs-keyword">string</span>&gt; <span class="hljs-title">UpdateAsync</span>(<span class="hljs-params">UserDto user</span>)</span>;
    <span class="hljs-function">Task&lt;<span class="hljs-keyword">string</span>&gt; <span class="hljs-title">DeleteAsync</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> id</span>)</span>;
}
</code></pre>
<p>Ambas as interfaces foram posicionadas na pasta <code>Application/Interfaces</code>, pois essa camada representa a lógica da aplicação (application layer), isto é , o ponto de comunicação entre as regras de negócio e as implementações concretas.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> OracleCrud.Sp.Api.Domain.Dtos;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">OracleCrud.Sp.Api.Application.Interfaces</span>;

<span class="hljs-keyword">public</span> <span class="hljs-keyword">interface</span> <span class="hljs-title">IUserRepository</span>
{
    Task&lt;IEnumerable&lt;UserDto&gt;&gt; GetAllAsync();
    <span class="hljs-function">Task&lt;<span class="hljs-keyword">string</span>&gt; <span class="hljs-title">InsertAsync</span>(<span class="hljs-params">UserDto user</span>)</span>;
    <span class="hljs-function">Task&lt;<span class="hljs-keyword">string</span>&gt; <span class="hljs-title">UpdateAsync</span>(<span class="hljs-params">UserDto user</span>)</span>;
    <span class="hljs-function">Task&lt;<span class="hljs-keyword">string</span>&gt; <span class="hljs-title">DeleteAsync</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> id</span>)</span>;
}
</code></pre>
<p>Manter as interfaces nesse local centraliza os contratos da aplicação, facilitando a leitura, os testes e futuras substituições de implementação (por exemplo, trocar Oracle por outro banco, sem impactar as camadas superiores). Essa decisão segue os princípios da arquitetura limpa promovendo uma baixo acoplamento e e facilitando a manutenção da solução.</p>
<h2 id="heading-conclusao">Conclusão</h2>
<p>Nesta <strong>Parte 1</strong> da série <em>Construindo a API REST em .NET com Oracle XE e Stored Procedures</em>, iniciamos o desenvolvimento da aplicação partindo totalmente do zero. Realizamos a seguintes etapas:</p>
<ul>
<li><p>Criamos o projeto com o template <strong>ASP.NET Core Web API</strong> no <strong>Visual Studio 2022</strong>;</p>
</li>
<li><p>Limpamos a estrutura inicial removendo arquivos de exemplo como <code>WeatherForecast.cs</code> e <code>WeatherForecastController.cs</code>;</p>
</li>
<li><p>Organizamos a base do projeto como uma estrutura em camadas: <code>Domain</code>, <code>Application</code>, <code>Infrastructure</code> e <code>Controllers</code>;</p>
</li>
<li><p>Definimos os DTOs <code>CreateUserDto</code> e <code>UserDto</code>, explicando seus papéis e porque estão posicionados dentro da camada de domínio;</p>
</li>
<li><p>Criamos as interfaces <code>IUserService</code> e <code>IUserRepository</code>, que representam os contratos da camada de aplicação.</p>
</li>
<li><p>Justificamos a separação das interfaces em Application/Interfaces, mantendo o foco em uma arquitetura limpa e desacoplada.</p>
</li>
</ul>
<p>Na <strong>Parte 2</strong>, vamos dar continuidade à implementação, criando os repositórios concretos, integrando com o banco <strong>Oracle XE</strong> por meio de Stored Procedures e finalizando os endpoints da nossa <strong>API REST</strong>.</p>
]]></content:encoded></item><item><title><![CDATA[Instalando Oracle XE no WSL2 (Windows 11)]]></title><description><![CDATA[Este tutorial mostra como instalar e executar o Oracle Database Express Edition (XE) via Docker, usando o Ubuntu no WSL2 dentro do Windows 11, com uma imagem oficial da Oracle. Essa configuração é ideal para fins de estudo, testes e desenvolvimento l...]]></description><link>https://www.codigobasico.com.br/instalando-oracle-xe-no-wsl2-windows-11</link><guid isPermaLink="true">https://www.codigobasico.com.br/instalando-oracle-xe-no-wsl2-windows-11</guid><category><![CDATA[Oracle]]></category><category><![CDATA[Docker]]></category><category><![CDATA[wsl2]]></category><category><![CDATA[dbeaver]]></category><category><![CDATA[database]]></category><category><![CDATA[Tutorial]]></category><dc:creator><![CDATA[Flavio dos Santos]]></dc:creator><pubDate>Tue, 22 Jul 2025 13:24:31 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1753190338329/b6b20a0f-f727-4581-97c4-cdcbab92fa22.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Este tutorial mostra como instalar e executar o Oracle Database Express Edition (XE) via Docker, usando o Ubuntu no WSL2 dentro do Windows 11, com uma imagem oficial da Oracle. Essa configuração é ideal para fins de estudo, testes e desenvolvimento local, sem a necessidade de instalar o Oracle diretamente no sistema operacional.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">⚠</div>
<div data-node-type="callout-text">Nota: Este tutorial não aborda a instalação ou configuração do WSL2 nem do Ubuntu LTS. Pressupões que você já tem o Ubuntu e Docker rodando no WSL2.</div>
</div>

<h2 id="heading-criacao-do-volume">Criação do Volume</h2>
<p>No <strong>Docker</strong>, volumes são usados para armazenar dados de forma persistente fora do ciclo de vida dos containers. No caso do <strong>Oracle XE</strong>, isso significa garantir que os dados do banco não se percam ao reiniciar ou remover o container. O comando abaixo cria um volume nomeado chamado <code>oracle-xe-data</code>, que será utilizado para armazenar os arquivos do banco Oracle de forma durável:</p>
<pre><code class="lang-sql">docker volume <span class="hljs-keyword">create</span> <span class="hljs-keyword">oracle</span>-xe-<span class="hljs-keyword">data</span>
</code></pre>
<p>Esse volume será montando no container posteriormente, garantindo que os dados persistam entre reinicializações e recriações do ambiente.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text"><strong>Importante</strong>: Quando usado no contexto <strong>WSL2</strong>(Windows Subsystem for Linux 2), esse volume garante que os dados não serão perdidos mesmo após reiniciar o WSL2 ou próprio Windows. Ou seja, a base de dados continuará intacta após o sistema ser desligado ou reiniciado.</div>
</div>

<h2 id="heading-criando-o-container">Criando o Container</h2>
<p>Após criar o volume para persistência dos dados, o próximo passo é iniciar o container do <strong>Oracle XE</strong>. Isso é feito por meio do comando <code>docker run</code>, que define diversas configurações importantes para o ambiente do banco de dados, como nome do container, portas de acesso, senha do usuário administrador e o volume a ser utilizado. Esse comando também garante que o banco de dados seja reiniciado automaticamente sempre que o Docker (ou o sistema, como o WSL2) for reiniciado. Abaixo está o comando completo que realiza essa configuração:</p>
<pre><code class="lang-bash">docker run -d \
  --name oracle-xe \
  --restart unless-stopped \
  -p 1521:1521 \
  -p 5500:5500 \
  -e ORACLE_PWD=MinhaSenha123 \
  -v oracle-xe-data:/opt/oracle/oradata \
  container-registry.oracle.com/database/express:21.3.0-xe
</code></pre>
<p>O que esse comando faz:</p>
<ul>
<li><p><code>-name oracle-exe</code>: Nome do container;</p>
</li>
<li><p><code>-p 1521:1521</code>: Expõe a porta padrão do Oracle;</p>
</li>
<li><p><code>-p 5500:5500</code>: Acesso ao Enterprise Manager (Gui web);</p>
</li>
<li><p><code>-e ORACLE_PWD=...</code>: Define a senha do usuário <strong>system</strong>;</p>
</li>
<li><p><code>-v oracle-xe-data:/opt/oracle/oradata</code>: Monta o volume nomeado <code>oracle-xe-data</code> no diretório onde o Oracle XE armazena os dados. Isso garante que as informações do banco sejam preservadas mesmo após reiniciar o container, o WSL2 ou o sistema operacional.</p>
</li>
<li><p><code>Última linha</code>: Define a imagem <strong>Oracle XE 21c</strong>.</p>
</li>
</ul>
<h2 id="heading-conectando-ao-oracle-xe-com-o-dbeaver-community">Conectando ao Oracle XE com o DBeaver Community</h2>
<p>O <strong>DBeaver Community</strong> é uma ferramenta gráfica gratuita e de código aberto utilizada para acessar e gerenciar bancos de dados. Compatível com uma variedade de SGBDs (incluindo <strong>Oracle</strong>, MySQL, PostgreSQL, SQL Server, entre outros), essa ferramenta oferece uma interface intuitiva que facilita a execução de comandos SQL, criação de objetos no banco (como tabelas, procedures e views), além de visualização e edição de dados.</p>
<p>No contexto deste material, utilizamos o <strong>DBeaver</strong> para conectar ao <strong>Oracle XE</strong> rodando dentro <strong>WSL2</strong> via <strong>Docker</strong>, permitindo uma interação simples e eficaz com o banco de dados diretamente da interface gráfica.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753187804974/4fef1d12-a79d-4f1a-b4c1-7cddc534134b.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-configurando-a-conexao-dbeaver-para-acessar-o-oracle-xe">Configurando a conexão DBeaver para acessar o Oracle XE</h3>
<p>Para que o <strong>DBeaver</strong> consiga se comunicar corretamente com o <strong>Oracle XE</strong> executando em um container <strong>Docker</strong> (via <strong>WSL2</strong>), é necessário configurar manualmente os parâmetros de conexão. essa etapa informa ao <strong>DBeaver</strong> onde o banco está rodando, quais portas estão expostas, qual serviço utilizar e quais credenciais devem ser fornecidas.</p>
<p>Passo a passo:</p>
<ol>
<li><p>Abra o DBeaver;</p>
</li>
<li><p>Clique em Arquivo &gt; Nova Conexão (ou no ícone de nova conexão);</p>
</li>
<li><p>Na lista de banco de dados, selecione Oracle e clique em Avançar;</p>
</li>
<li><p>Preencha os campos de conexão:</p>
<ol>
<li><p>Host: localhost;</p>
</li>
<li><p>Porta: 1521;</p>
</li>
<li><p>Serviço (Service): XEPDB1;</p>
</li>
<li><p>Usuário: system (ou outro usuário criado, como app_user);</p>
</li>
<li><p>Senha: a senha definida como parâmetro <code>ORACLE_PWD</code> no container (ex: <code>MinhaSenha123</code>).</p>
</li>
</ol>
</li>
<li><p>Clique em “Testar Conexão” para validar a comunicação com o banco;</p>
</li>
<li><p>Se solicitado, permita o download do driver Oracle JDBC;</p>
</li>
<li><p>Clique em Concluir. A conexão será adicionada à barra lateral esquerda, pronta para ser utilizada.</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753188860626/f0cb0f1c-27f2-4d84-99ad-b5fa9ed21078.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-visualizando-os-containers-de-forma-personalizada">Visualizando os containers de forma personalizada</h2>
<p>O comando abaixo permite listar apenas as informações mais úteis dos containers em execução, com uma visualização mais limpa e organizada:</p>
<pre><code class="lang-bash">docker ps --format <span class="hljs-string">"table {{.ID}}\t{{.Names}}\t{{.CreatedAt}}\t{{.Status}}\t{{.Ports}}"</span>
</code></pre>
<p>Esse comando usa a flag <code>--format</code>, que permite personalizar as colunas exibidas. Neste caso, estamos pedindo para mostrar os seguintes campos:</p>
<ul>
<li><p><code>{{.ID}}</code>: O identificador único do container;</p>
</li>
<li><p><code>{{.Names}}</code>: O nome que você deu ao container (exemplo: oracle-xe);</p>
</li>
<li><p><code>{{.CreatedAt}}</code>: A data e hora em que o container foi criado;</p>
</li>
<li><p><code>{{.Status}}</code>: O estado atual do container (exemplo: “Up 5 minutes”);</p>
</li>
<li><p><code>{{.Ports}}</code>: Quais portas estão xpostas/mapeadas para o host.</p>
</li>
</ul>
<p>A palavra <code>table</code> no início instrui o Docker a exibi os dados em formato tabular (com cabeçalho), e os <code>\t</code> inserem tabulações entre as colunas para melhorar a legibilidade. Esse formato é ideal para uso no terminal durante o desenvolvimento, especialmente quando você quer rapidamente visualizar o status de containers importantes sem excesso de informações.</p>
<h3 id="heading-por-que-criar-um-usuario-dedicado-para-o-acesso-da-aplicacao">Por que criar um usuário dedicado para o acesso da aplicação?</h3>
<p>Ao trabalhar com banco de dados Oracle(ou qualquer outro), uma boa prática essencial é nunca usar usuários administradores como <code>SYSTEM</code> ou <code>SYS</code> em aplicações. Esses usuários possuem permissões elevadas e são voltados para administração do banco, não para uso em aplicações do dia a dia.</p>
<p>Criar um usuário dedicado, como <code>app_user</code>, traz várias vantagens:</p>
<ul>
<li><p><strong>Segurança</strong>: Limita os acessos ao estritamente necessário, evitando alterações acidentais em objetos críticos do banco;</p>
</li>
<li><p><strong>Organização</strong>: Os objetos (tabelas, views, procedures) da aplicação ficam concentrados em um schema próprio;</p>
</li>
<li><p><strong>Facilidade de manutenção</strong>: Caso o acesso precise ser revogado, migrado ou auditado, tudo está isolado por usuário;</p>
</li>
<li><p><strong>Boas práticas de arquitetura</strong>: Em ambientes profissionais, é comum um banco de dados ter vários usuários(schemas), cada um representando um serviço ou módulo da aplicação.</p>
</li>
</ul>
<p>O comando abaixo cria um novo usuário no banco com a senha <code>app123</code> e concede permissões básicas para o usuário se conectar ao banco e criar objetos como tabelas, view e procedimentos.</p>
<pre><code class="lang-sql"><span class="hljs-comment">-- Criação do usuário</span>
<span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">USER</span> app_user <span class="hljs-keyword">IDENTIFIED</span> <span class="hljs-keyword">BY</span> app123;

<span class="hljs-comment">-- Permissões básicas para criar e usar tabelas</span>
<span class="hljs-keyword">GRANT</span> <span class="hljs-keyword">CONNECT</span>, <span class="hljs-keyword">RESOURCE</span> <span class="hljs-keyword">TO</span> app_user;

<span class="hljs-keyword">GRANT</span> <span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">VIEW</span> <span class="hljs-keyword">TO</span> app_user;
</code></pre>
<p>Você pode se conectar com esse usuário no DBeaver ou via backend .NET usando a seguinte string de conexão:</p>
<pre><code class="lang-json"><span class="hljs-string">"User Id=app_user;Password=app123;Data Source=localhost:1521/XEPDB1;"</span>
</code></pre>
<p>Abaixo a tabela de armazenamento de usuários:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-keyword">users</span> (
    <span class="hljs-keyword">id</span> <span class="hljs-built_in">VARCHAR2</span>(<span class="hljs-number">36</span>) PRIMARY <span class="hljs-keyword">KEY</span>,
    <span class="hljs-keyword">name</span> <span class="hljs-built_in">VARCHAR2</span>(<span class="hljs-number">100</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
    email <span class="hljs-built_in">VARCHAR2</span>(<span class="hljs-number">150</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>
);

<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> <span class="hljs-keyword">users</span> (<span class="hljs-keyword">id</span>, <span class="hljs-keyword">name</span>, email)
<span class="hljs-keyword">VALUES</span> (<span class="hljs-string">'550e8400-e29b-41d4-a716-446655440000'</span>, <span class="hljs-string">'Alice'</span>, <span class="hljs-string">'alice@example.com'</span>);
</code></pre>
<h2 id="heading-regras-de-negocio-no-banco-de-dados">Regras de Negócio no Banco de Dados</h2>
<p>Em sistemas modernos, é comum que as regras de negócio sejam implementadas na camada do backend, onde frameworks e linguagens de programação oferecem maior flexibilidade e controle. No entanto ainda existem cenários em que parte ou toda a lógica é mantida no banco de dados, especialmente em sistemas legados, ambientes internos mais controlados ou soluções com baixa complexidade, onde centralizar a lógica no banco pode facilitar o controle de integridade e reduzir a dependência de outras camadas. Nesta seção, veremos um exemplo prático e didático de como encapsular regras de negócio diretamente no <strong>Oracle</strong> usando <strong>PL/SQL</strong>, com stored procedures responsáveis por operações como inserção, atualização, exclusão e consulta de dados.</p>
<h3 id="heading-insercao-com-plsql">Inserção com PL/SQL</h3>
<p>A stored procedure <code>sp_insert_user</code> demonstra como implementar a inserção de dados com validação diretamente no banco de dados, centralizando a regra de negócio no Oracle. Embora essa abordagem não seja comum em arquiteturas modernas voltadas à alta escalabilidade, ela ainda pode ser útil em sistemas internos, legados ou como exercício didático para ilustrar o uso do PL/SQL para controle de integridade e regras no lado do banco.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">OR</span> <span class="hljs-keyword">REPLACE</span> <span class="hljs-keyword">PROCEDURE</span> app_user.sp_insert_user (
    p_id     <span class="hljs-keyword">IN</span> <span class="hljs-built_in">VARCHAR2</span>,
    p_name   <span class="hljs-keyword">IN</span> <span class="hljs-built_in">VARCHAR2</span>,
    p_email  <span class="hljs-keyword">IN</span> <span class="hljs-built_in">VARCHAR2</span>,
    p_result <span class="hljs-keyword">OUT</span> <span class="hljs-built_in">VARCHAR2</span>
) <span class="hljs-keyword">AS</span>
<span class="hljs-keyword">BEGIN</span>
    <span class="hljs-comment">-- Validações básicas</span>
    <span class="hljs-keyword">IF</span> p_id <span class="hljs-keyword">IS</span> <span class="hljs-literal">NULL</span> <span class="hljs-keyword">OR</span> <span class="hljs-keyword">TRIM</span>(p_id) <span class="hljs-keyword">IS</span> <span class="hljs-literal">NULL</span> <span class="hljs-keyword">THEN</span>
        p_result := <span class="hljs-string">'O campo ID é obrigatório.'</span>;
        RETURN;
    ELSIF p_name IS NULL OR TRIM(p_name) IS NULL THEN
        p_result := 'O campo Nome é obrigatório.';
        RETURN;
    ELSIF p_email IS NULL OR TRIM(p_email) IS NULL THEN
        p_result := 'O campo E-mail é obrigatório.';
        RETURN;
    <span class="hljs-keyword">END</span> <span class="hljs-keyword">IF</span>;

    <span class="hljs-comment">-- Inserção no banco</span>
    <span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> app_user.users (<span class="hljs-keyword">id</span>, <span class="hljs-keyword">name</span>, email)
    <span class="hljs-keyword">VALUES</span> (p_id, p_name, p_email);

    p_result := 'Usuário inserido com sucesso.';

EXCEPTION
    WHEN OTHERS THEN
        p_result := 'Erro: ' || SQLERRM;
<span class="hljs-keyword">END</span>;
</code></pre>
<p>Alteração</p>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">OR</span> <span class="hljs-keyword">REPLACE</span> <span class="hljs-keyword">PROCEDURE</span> app_user.sp_update_user (
    p_id     <span class="hljs-keyword">IN</span> <span class="hljs-built_in">VARCHAR2</span>,
    p_name   <span class="hljs-keyword">IN</span> <span class="hljs-built_in">VARCHAR2</span>,
    p_email  <span class="hljs-keyword">IN</span> <span class="hljs-built_in">VARCHAR2</span>,
    p_result <span class="hljs-keyword">OUT</span> <span class="hljs-built_in">VARCHAR2</span>
)
<span class="hljs-keyword">IS</span>
<span class="hljs-keyword">BEGIN</span>
    <span class="hljs-comment">-- Validações básicas</span>
    <span class="hljs-keyword">IF</span> p_id <span class="hljs-keyword">IS</span> <span class="hljs-literal">NULL</span> <span class="hljs-keyword">OR</span> <span class="hljs-keyword">TRIM</span>(p_id) <span class="hljs-keyword">IS</span> <span class="hljs-literal">NULL</span> <span class="hljs-keyword">THEN</span>
        p_result := <span class="hljs-string">'Erro: O campo ID é obrigatório.'</span>;
        RETURN;
    ELSIF p_name IS NULL OR TRIM(p_name) IS NULL THEN
        p_result := 'Erro: O campo Nome é obrigatório.';
        RETURN;
    ELSIF p_email IS NULL OR TRIM(p_email) IS NULL THEN
        p_result := 'Erro: O campo E-mail é obrigatório.';
        RETURN;
    <span class="hljs-keyword">END</span> <span class="hljs-keyword">IF</span>;

    <span class="hljs-comment">-- Atualização no banco</span>
    <span class="hljs-keyword">UPDATE</span> app_user.users
    <span class="hljs-keyword">SET</span> <span class="hljs-keyword">name</span> = p_name,
        email = p_email
    <span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">id</span> = p_id;

    <span class="hljs-comment">-- Verifica se algum registro foi atualizado</span>
    IF SQL%ROWCOUNT = 0 THEN
        p_result := 'Erro: Usuário não encontrado.';
    ELSE
        p_result := 'Usuário atualizado com sucesso.';
    <span class="hljs-keyword">END</span> <span class="hljs-keyword">IF</span>;
<span class="hljs-keyword">END</span>;
</code></pre>
<p>exclusão</p>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">OR</span> <span class="hljs-keyword">REPLACE</span> <span class="hljs-keyword">PROCEDURE</span> app_user.sp_delete_user (
    p_id     <span class="hljs-keyword">IN</span> <span class="hljs-built_in">VARCHAR2</span>,
    p_result <span class="hljs-keyword">OUT</span> <span class="hljs-built_in">VARCHAR2</span>
)
<span class="hljs-keyword">IS</span>
<span class="hljs-keyword">BEGIN</span>
    <span class="hljs-keyword">IF</span> p_id <span class="hljs-keyword">IS</span> <span class="hljs-literal">NULL</span> <span class="hljs-keyword">OR</span> <span class="hljs-keyword">TRIM</span>(p_id) <span class="hljs-keyword">IS</span> <span class="hljs-literal">NULL</span> <span class="hljs-keyword">THEN</span>
        p_result := <span class="hljs-string">'Erro: O campo ID é obrigatório.'</span>;
        RETURN;
    <span class="hljs-keyword">END</span> <span class="hljs-keyword">IF</span>;

    <span class="hljs-keyword">DELETE</span> <span class="hljs-keyword">FROM</span> app_user.users
    <span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">id</span> = p_id;

    IF SQL%ROWCOUNT = 0 THEN
        p_result := 'Erro: Usuário não encontrado.';
    ELSE
        p_result := 'Usuário excluí<span class="hljs-keyword">do</span> com sucesso.<span class="hljs-string">';
    END IF;
END;</span>
</code></pre>
<p>View</p>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">OR</span> <span class="hljs-keyword">REPLACE</span> <span class="hljs-keyword">VIEW</span> app_user.vw_users <span class="hljs-keyword">AS</span>
<span class="hljs-keyword">SELECT</span>
    <span class="hljs-keyword">id</span>,
    <span class="hljs-keyword">name</span>,
    email
<span class="hljs-keyword">FROM</span>
    app_user.users;
</code></pre>
]]></content:encoded></item><item><title><![CDATA[Uso do (chore) nos Commits GitHub]]></title><description><![CDATA[O que significa o (chore) em uma mensagem de commit?
Ao trabalhar com Git, é comum registrar tudo o que foi alterado no código por meio de commits. Para facilitar a leitura do histórico desses commits, muitos times seguem uma convenção chamada Conven...]]></description><link>https://www.codigobasico.com.br/uso-do-chore-nos-commits-github</link><guid isPermaLink="true">https://www.codigobasico.com.br/uso-do-chore-nos-commits-github</guid><category><![CDATA[Git]]></category><category><![CDATA[GitHub]]></category><category><![CDATA[commits]]></category><category><![CDATA[conventional commits]]></category><category><![CDATA[#desenvolvimento]]></category><category><![CDATA[boaspraticas]]></category><category><![CDATA[Boas Práticas de Programação]]></category><category><![CDATA[version control]]></category><dc:creator><![CDATA[Flavio dos Santos]]></dc:creator><pubDate>Fri, 18 Jul 2025 17:47:14 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1752860112389/c08b5385-53a3-4e6a-89a3-239408d3d730.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-o-que-significa-o-chore-em-uma-mensagem-de-commit">O que significa o (chore) em uma mensagem de commit?</h2>
<p>Ao trabalhar com <strong>Git</strong>, é comum registrar tudo o que foi alterado no código por meio de commits. Para facilitar a leitura do histórico desses commits, muitos times seguem uma convenção chamada <em>Conventional Commits</em>, onde cada commit começa com uma palavra-chave que indica o tipo de mudança realizada. Um desses tipos é o <code>chore</code>.</p>
<p>A palavra <code>chore</code> vem do inglês e significa algo como “tarefa rotineira” ou “serviços doméstico”. No contexto do <strong>Git</strong>, ela é usada indicar mudanças que fazem parte da manutenção do projeto, mas que não afetam diretamente o código da aplicação ou o comportamento visível para o usuário.</p>
<h2 id="heading-quando-usar-o-chore">Quando usar o (chore)?</h2>
<p>Você deve usar o <code>chore</code> sempre que estiver fazendo alterações que não envolvem novas funcionalidades, correções de bugs ou melhorias diretas no código. Isso inclui, por exemplo:</p>
<ul>
<li><p>Adicionar ou atualizar arquivos como <code>.gitignore</code>, <code>tsconfig.json</code>, <code>.editorconfig</code> ou arquivos de ambiente;</p>
</li>
<li><p>Alterar scripts de automação, como build, deploy ou testes automatizados;</p>
</li>
<li><p>Atualizar dependências de ferramentas internas, mas sem impactar o funcionamento da aplicação;</p>
</li>
<li><p>Mover pastas, renomear arquivos ou limpar código não utilizado.</p>
</li>
</ul>
<p>Essas informações são importantes para manter o projeto saudável e bem organizado, mas não mudam “o que o sistema faz”. Por isso, eles recebem esse rótulo especial.</p>
<h2 id="heading-exemplos-de-uso-com-chore">Exemplos de uso com (chore)</h2>
<p>Aqui estão exemplos reais de mensagens de commit usando o prefixo <code>chore</code>, com o emoji 🛠️ para facilitar a leitura:</p>
<pre><code class="lang-bash">git commit -m <span class="hljs-string">"🛠️ chore: adiciona regra *.bkp ao .gitignore."</span>
git commit -m <span class="hljs-string">"🛠️ chore: atualiza dependências internas do projeto."</span>
git commit -m <span class="hljs-string">"🛠️ chore: remove arquivos temporários não utilizados."</span>
git commit -m <span class="hljs-string">"🛠️ chore: reorganiza estrutura de diretórios."</span>
git commit -m <span class="hljs-string">"🛠️ chore: ajusta script de build para ambiente local."</span>
</code></pre>
<p>Esses exemplos mostram como o <code>chore</code> é usado para marcar tarefas que ajudam na manutenção do projeto, sem interferir diretamente no comportamento do software.</p>
]]></content:encoded></item></channel></rss>