<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="http://old-blog.ralms.io/feed.xml" rel="self" type="application/atom+xml" /><link href="http://old-blog.ralms.io/" rel="alternate" type="text/html" /><updated>2026-01-04T16:34:20-03:00</updated><id>http://old-blog.ralms.io/feed.xml</id><title type="html">Ralms.IO</title><subtitle>Rafael Almeida, Entity Framework Core, gRPC, Apache Kafka, ScyllaDB, Brazil, Dicas e Truques, C#, Performance, Performance .NET, Dicas EF Core, Advanced, Acesso a dados, Banco de dados, .NET Core, .NET 5, ASP.NET Core, ASP.NET 5, System.Text.JSON, JSON, Microsoft, Microsoft .NET, DOTNET CORE</subtitle><author><name>Rafael Almeida</name><email>ralms@ralms.net</email></author><entry><title type="html">EntityFramework Core - SnakeCase</title><link href="http://old-blog.ralms.io/dica/entity%20framework%20core/snakecase-intro/" rel="alternate" type="text/html" title="EntityFramework Core - SnakeCase" /><published>2023-07-28T00:00:00-03:00</published><updated>2023-07-28T00:00:00-03:00</updated><id>http://old-blog.ralms.io/dica/entity%20framework%20core/snakecase-intro</id><content type="html" xml:base="http://old-blog.ralms.io/dica/entity%20framework%20core/snakecase-intro/"><![CDATA[<p><img src="http://old-blog.ralms.io/assets/images/dicasefcore.png" alt="01" /></p>

<center><strong>Fala pessoal, tudo bem?! 💚</strong></center>
<hr />

<p>Veja como fazer convenções de nomenclatura <strong>SnakeCase</strong> para o <strong>EntityFramework Core!</strong><br />
<br />
<img src="http://old-blog.ralms.io/assets/images/camelsnakecase.jpg" alt="01" /></p>
<div class="notice--warning">
<strong>FYI:</strong><br />
Nosso <strong>objetivo</strong> aqui é mostrar uma solução para o <strong>EntityFramework Core + PostgreSQL.</strong><br />
Basicamente existem 4 tipos de nomenclaturas que usamos para escrever nossos códigos: <strong>PascalCase, CamelCase, SnakeCase e SpinalCase</strong>, já que iremos abordar um assunto que se trata de um dos casos citados, nada mais justo do que resumir cada um deles.
</div>
<p><img src="http://old-blog.ralms.io/assets/images/tipocase.png" alt="01" /></p>

<h1 id="resumidão">ResumidÃO!</h1>

<h2 id="pascalcase">PascalCase</h2>
<div style="text-align: justify;">
Usando Pascal Case em nosso código significa que a primeira letra de cada palavra para o identificador deverá ser maiúscula.<br />
<strong style="color: green">Exemplo:</strong> 
</div>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">BlogRafael</span> <span class="p">=</span> <span class="s">"www.ralms.io"</span><span class="p">;</span>
</code></pre></div></div>
<h2 id="camelcase">CamelCase</h2>
<div style="text-align: justify;">
É o mesmo caso do Pascal Case, porém a primeira letra da primeira palavra é minúscula.<br />
<strong style="color: green">Exemplo:</strong> 
</div>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">blogRafael</span> <span class="p">=</span> <span class="s">"www.ralms.io"</span><span class="p">;</span>
</code></pre></div></div>
<h2 id="snakecase">SnakeCase</h2>
<div style="text-align: justify;">
Bom esse termo é bem legal e foi estabelecido por <strong>Jack Dahlgren</strong>, em 2002 quando trabalhava na Intel,
esse caso em especial, não tem uma definição especifica quando se trata em deixar as letras do identificador <strong>maiúsculo</strong> ou <strong>minúsculo</strong>, basicamente a regra pra ele é colocar um "_" entre as palavras do identificador.<br />
<strong style="color: green">Exemplo:</strong>
</div>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">blog_rafael</span> <span class="p">=</span> <span class="s">"www.ralms.io"</span><span class="p">;</span>
<span class="n">Blog_Rafael</span> <span class="p">=</span> <span class="s">"www.ralms.io"</span><span class="p">;</span>
</code></pre></div></div>

<h2 id="spinalcase">SpinalCase</h2>
<div style="text-align: justify;">
Mesma regra do <strong>SnakeCase</strong>, única diferença é em vez de usar "_", passaremos a utilizar "-" como separador de palavras.<br />
<strong style="color: green">Exemplo:</strong>
</div>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">blog</span><span class="p">-</span><span class="n">rafael</span> <span class="p">=</span> <span class="s">"www.ralms.io"</span><span class="p">;</span>
<span class="n">Blog</span><span class="p">-</span><span class="n">Rafael</span> <span class="p">=</span> <span class="s">"www.ralms.io"</span><span class="p">;</span>
</code></pre></div></div>

<h1 id="vamos-codar">Vamos codar?!</h1>
<p><strong>O que me levou a escrever esse artigo?</strong></p>
<div style="text-align: justify;">
Foi a necessidade que eu tive e a improdutividade de ficar digitando aspas em torno dos campos e tabelas em minhas consultas <strong>PostgreSQL</strong>, isso mesmo,
eu sempre escrevi toda estrutura de meu banco com um <strong>DDL</strong> bem esquematizado.<br />
<br />Mas eu queria usar todo recurso que o <strong>EntityFramwork Core</strong> me proporciona, o EFCore por Design
cria os nomes de tabelas e campos por reflection, isso significa que se tiver uma propriedade <strong>PascalCase</strong>, da mesma forma será atribuido o nome a este,
existe a possibilidade de usarmos propriedades de sombras(ou Fluent API), mas esse é o trabalho que eu não gostaria de fazer e nem me procupar. <br />
<br />
Cada um tem sua forma de aplicar nomeclaturas em seus projetos, quando se trata banco de dados eu gosto de utilizar <strong>SnakeCase</strong>, 
acredito que é muito mais legível a leitura e suporte.<br />
<br />
E foi por isso que escrevi essa pequena extensão para nosso <strong>ModelBuilder</strong>, tudo isso por que aqueles que vem do <strong>SQL Server</strong> sabe que ele não se <strong>importa</strong> com maiúsculas e minúsculas para nomes de colunas e tabelas, cenário muito diferente para <strong>PostgreSQL</strong> que faz distinção entre maiúsculas e minúsculas,
mas aqui está a solução para isso, e então com alguns pequenos ajustes e uma simples função Regex, serei mais feliz 😄, <strong>VIVA REGEX</strong>!<br />
</div>
<p><br /></p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">static</span> <span class="k">class</span> <span class="nc">LinqSnakeCase</span>
<span class="p">{</span> 
    <span class="k">public</span> <span class="k">static</span> <span class="k">void</span> <span class="nf">ToSnakeNames</span><span class="p">(</span><span class="k">this</span> <span class="n">ModelBuilder</span> <span class="n">modelBuilder</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">entity</span> <span class="k">in</span> <span class="n">modelBuilder</span><span class="p">.</span><span class="n">Model</span><span class="p">.</span><span class="nf">GetEntityTypes</span><span class="p">())</span>
        <span class="p">{</span>
            <span class="n">entity</span><span class="p">.</span><span class="nf">Relational</span><span class="p">().</span><span class="n">TableName</span> <span class="p">=</span> <span class="n">entity</span><span class="p">.</span><span class="nf">Relational</span><span class="p">().</span><span class="n">TableName</span><span class="p">.</span><span class="nf">ToSnakeCase</span><span class="p">();</span>

            <span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">property</span> <span class="k">in</span> <span class="n">entity</span><span class="p">.</span><span class="nf">GetProperties</span><span class="p">())</span>
            <span class="p">{</span>
                <span class="n">property</span><span class="p">.</span><span class="nf">Relational</span><span class="p">().</span><span class="n">ColumnName</span> <span class="p">=</span> <span class="n">property</span>
                    <span class="p">.</span><span class="nf">Relational</span><span class="p">()</span>
                    <span class="p">.</span><span class="n">ColumnName</span>
                    <span class="p">.</span><span class="nf">ToSnakeCase</span><span class="p">();</span>
            <span class="p">}</span>

            <span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">key</span> <span class="k">in</span> <span class="n">entity</span><span class="p">.</span><span class="nf">GetKeys</span><span class="p">())</span>
            <span class="p">{</span>
                <span class="n">key</span><span class="p">.</span><span class="nf">Relational</span><span class="p">().</span><span class="n">Name</span> <span class="p">=</span> <span class="n">key</span><span class="p">.</span><span class="nf">Relational</span><span class="p">().</span><span class="n">Name</span><span class="p">.</span><span class="nf">ToSnakeCase</span><span class="p">();</span> 
            <span class="p">}</span>

            <span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">key</span> <span class="k">in</span> <span class="n">entity</span><span class="p">.</span><span class="nf">GetForeignKeys</span><span class="p">())</span>
            <span class="p">{</span>
                <span class="n">key</span><span class="p">.</span><span class="nf">Relational</span><span class="p">().</span><span class="n">Name</span> <span class="p">=</span> <span class="n">key</span><span class="p">.</span><span class="nf">Relational</span><span class="p">().</span><span class="n">Name</span><span class="p">.</span><span class="nf">ToSnakeCase</span><span class="p">();</span>
            <span class="p">}</span>

            <span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">index</span> <span class="k">in</span> <span class="n">entity</span><span class="p">.</span><span class="nf">GetIndexes</span><span class="p">())</span>
            <span class="p">{</span>
                <span class="n">index</span><span class="p">.</span><span class="nf">Relational</span><span class="p">().</span><span class="n">Name</span> <span class="p">=</span> <span class="n">index</span><span class="p">.</span><span class="nf">Relational</span><span class="p">().</span><span class="n">Name</span><span class="p">.</span><span class="nf">ToSnakeCase</span><span class="p">();</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="k">private</span> <span class="k">static</span> <span class="kt">string</span> <span class="nf">ToSnakeCase</span><span class="p">(</span><span class="k">this</span> <span class="kt">string</span> <span class="n">name</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="kt">string</span><span class="p">.</span><span class="nf">IsNullOrWhiteSpace</span><span class="p">(</span><span class="n">name</span><span class="p">)</span>
            <span class="p">?</span> <span class="n">name</span>
            <span class="p">:</span> <span class="n">Regex</span><span class="p">.</span><span class="nf">Replace</span><span class="p">(</span>
                <span class="n">name</span><span class="p">,</span> 
                <span class="s">@"([a-z0-9])([A-Z])"</span><span class="p">,</span> 
                <span class="s">"$1_$2"</span><span class="p">,</span> 
                <span class="n">RegexOptions</span><span class="p">.</span><span class="n">Compiled</span><span class="p">,</span>
                <span class="n">TimeSpan</span><span class="p">.</span><span class="nf">FromSeconds</span><span class="p">(</span><span class="m">1</span><span class="p">)).</span><span class="nf">ToLower</span><span class="p">();</span> 
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="veja-como-ficou-nosso-samplecontext">Veja como ficou nosso SampleContext</h2>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="nn">Microsoft.EntityFrameworkCore</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">System</span><span class="p">;</span>

<span class="k">namespace</span> <span class="nn">SnakeCase</span>
<span class="p">{</span>
    <span class="k">class</span> <span class="nc">Program</span>
    <span class="p">{</span>
        <span class="k">static</span> <span class="k">void</span> <span class="nf">Main</span><span class="p">(</span><span class="kt">string</span><span class="p">[]</span> <span class="n">args</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">db</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">SampleContext</span><span class="p">())</span>
            <span class="p">{</span>
                <span class="c1">// Nossa saída SQL</span>
                <span class="kt">var</span> <span class="n">script</span> <span class="p">=</span> <span class="n">db</span><span class="p">.</span><span class="n">Database</span><span class="p">.</span><span class="nf">GenerateCreateScript</span><span class="p">();</span>
            <span class="p">}</span>  
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">sealed</span> <span class="k">class</span> <span class="nc">SampleContext</span> <span class="p">:</span> <span class="n">DbContext</span>
    <span class="p">{</span>
        <span class="k">protected</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">OnConfiguring</span><span class="p">(</span><span class="n">DbContextOptionsBuilder</span> <span class="n">optionsBuilder</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="k">if</span> <span class="p">(!</span><span class="n">optionsBuilder</span><span class="p">.</span><span class="n">IsConfigured</span><span class="p">)</span>
            <span class="p">{</span>
                <span class="n">optionsBuilder</span><span class="p">.</span><span class="nf">UseNpgsql</span><span class="p">(</span>
                    <span class="s">"Host=127.0.0.1;Username=postgres;Password=XXX;Database=TestSnake"</span><span class="p">,</span> 
                    <span class="n">_</span> <span class="p">=&gt;</span> <span class="n">_</span><span class="p">.</span><span class="nf">EnableRetryOnFailure</span><span class="p">());</span>
            <span class="p">}</span>
        <span class="p">}</span>

        <span class="k">protected</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">OnModelCreating</span><span class="p">(</span><span class="n">ModelBuilder</span> <span class="n">modelo</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="n">modelo</span><span class="p">.</span><span class="n">Entity</span><span class="p">&lt;</span><span class="n">TestSnakeCase</span><span class="p">&gt;();</span>

            <span class="c1">// Aqui está nossa mágica!</span>
            <span class="n">modelo</span><span class="p">.</span><span class="nf">ToSnakeNames</span><span class="p">();</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">class</span> <span class="nc">TestSnakeCase</span>
    <span class="p">{</span>
        <span class="k">public</span> <span class="kt">int</span> <span class="n">Id</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
        <span class="k">public</span> <span class="kt">int</span> <span class="n">CodigoIBGE</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
        <span class="k">public</span> <span class="kt">string</span> <span class="n">NomeCompleto</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span> 
        <span class="k">public</span> <span class="kt">int</span> <span class="n">AnoNascimento</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
        <span class="k">public</span> <span class="n">DateTime</span> <span class="n">DataCadastro</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="nossa-saída-sql">Nossa saída SQL</h2>
<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">CREATE</span> <span class="k">TABLE</span> <span class="n">test_snake_case</span> <span class="p">(</span>
    <span class="n">id</span> <span class="nb">serial</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span>
    <span class="n">codigo_ibge</span> <span class="nb">integer</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span>
    <span class="n">nome_completo</span> <span class="nb">text</span> <span class="k">NULL</span><span class="p">,</span>
    <span class="n">ano_nascimento</span> <span class="nb">integer</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span>
    <span class="n">data_cadastro</span> <span class="nb">timestamp</span> <span class="k">without</span> <span class="nb">time</span> <span class="k">zone</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span>
    <span class="k">CONSTRAINT</span> <span class="n">pk_test_snake_case</span> <span class="k">PRIMARY</span> <span class="k">KEY</span> <span class="p">(</span><span class="n">id</span><span class="p">)</span>
<span class="p">);</span>
</code></pre></div></div>
<p><br /></p>

<div class="notice--success">
<strong>
 Pessoal fico por aqui e um forte abraço! 😄 
 </strong>
</div>

<p>#mvpbuzz #mvpbr #mvp #developerssergipe #share #vscode #postgresql #efcore<br /><br /></p>]]></content><author><name>Rafael Almeida</name><email>ralms@ralms.net</email></author><category term="Dica" /><category term="Entity Framework Core" /><summary type="html"><![CDATA[Fala pessoal, tudo bem?! 💚 Veja como fazer convenções de nomenclatura SnakeCase para o EntityFramework Core! FYI: Nosso objetivo aqui é mostrar uma solução para o EntityFramework Core + PostgreSQL. Basicamente existem 4 tipos de nomenclaturas que usamos para escrever nossos códigos: PascalCase, CamelCase, SnakeCase e SpinalCase, já que iremos abordar um assunto que se trata de um dos casos citados, nada mais justo do que resumir cada um deles. ResumidÃO! PascalCase Usando Pascal Case em nosso código significa que a primeira letra de cada palavra para o identificador deverá ser maiúscula. Exemplo: BlogRafael = "www.ralms.io"; CamelCase É o mesmo caso do Pascal Case, porém a primeira letra da primeira palavra é minúscula. Exemplo: blogRafael = "www.ralms.io"; SnakeCase Bom esse termo é bem legal e foi estabelecido por Jack Dahlgren, em 2002 quando trabalhava na Intel, esse caso em especial, não tem uma definição especifica quando se trata em deixar as letras do identificador maiúsculo ou minúsculo, basicamente a regra pra ele é colocar um "_" entre as palavras do identificador. Exemplo: blog_rafael = "www.ralms.io"; Blog_Rafael = "www.ralms.io"; SpinalCase Mesma regra do SnakeCase, única diferença é em vez de usar "_", passaremos a utilizar "-" como separador de palavras. Exemplo: blog-rafael = "www.ralms.io"; Blog-Rafael = "www.ralms.io"; Vamos codar?! O que me levou a escrever esse artigo? Foi a necessidade que eu tive e a improdutividade de ficar digitando aspas em torno dos campos e tabelas em minhas consultas PostgreSQL, isso mesmo, eu sempre escrevi toda estrutura de meu banco com um DDL bem esquematizado. Mas eu queria usar todo recurso que o EntityFramwork Core me proporciona, o EFCore por Design cria os nomes de tabelas e campos por reflection, isso significa que se tiver uma propriedade PascalCase, da mesma forma será atribuido o nome a este, existe a possibilidade de usarmos propriedades de sombras(ou Fluent API), mas esse é o trabalho que eu não gostaria de fazer e nem me procupar. Cada um tem sua forma de aplicar nomeclaturas em seus projetos, quando se trata banco de dados eu gosto de utilizar SnakeCase, acredito que é muito mais legível a leitura e suporte. E foi por isso que escrevi essa pequena extensão para nosso ModelBuilder, tudo isso por que aqueles que vem do SQL Server sabe que ele não se importa com maiúsculas e minúsculas para nomes de colunas e tabelas, cenário muito diferente para PostgreSQL que faz distinção entre maiúsculas e minúsculas, mas aqui está a solução para isso, e então com alguns pequenos ajustes e uma simples função Regex, serei mais feliz 😄, VIVA REGEX! public static class LinqSnakeCase { public static void ToSnakeNames(this ModelBuilder modelBuilder) { foreach (var entity in modelBuilder.Model.GetEntityTypes()) { entity.Relational().TableName = entity.Relational().TableName.ToSnakeCase(); foreach (var property in entity.GetProperties()) { property.Relational().ColumnName = property .Relational() .ColumnName .ToSnakeCase(); } foreach (var key in entity.GetKeys()) { key.Relational().Name = key.Relational().Name.ToSnakeCase(); } foreach (var key in entity.GetForeignKeys()) { key.Relational().Name = key.Relational().Name.ToSnakeCase(); } foreach (var index in entity.GetIndexes()) { index.Relational().Name = index.Relational().Name.ToSnakeCase(); } } } private static string ToSnakeCase(this string name) { return string.IsNullOrWhiteSpace(name) ? name : Regex.Replace( name, @"([a-z0-9])([A-Z])", "$1_$2", RegexOptions.Compiled, TimeSpan.FromSeconds(1)).ToLower(); } } Veja como ficou nosso SampleContext using Microsoft.EntityFrameworkCore; using System; namespace SnakeCase { class Program { static void Main(string[] args) { using (var db = new SampleContext()) { // Nossa saída SQL var script = db.Database.GenerateCreateScript(); } } } public sealed class SampleContext : DbContext { protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { if (!optionsBuilder.IsConfigured) { optionsBuilder.UseNpgsql( "Host=127.0.0.1;Username=postgres;Password=XXX;Database=TestSnake", _ =&gt; _.EnableRetryOnFailure()); } } protected override void OnModelCreating(ModelBuilder modelo) { modelo.Entity&lt;TestSnakeCase&gt;(); // Aqui está nossa mágica! modelo.ToSnakeNames(); } } public class TestSnakeCase { public int Id { get; set; } public int CodigoIBGE { get; set; } public string NomeCompleto { get; set; } public int AnoNascimento { get; set; } public DateTime DataCadastro { get; set; } } } Nossa saída SQL CREATE TABLE test_snake_case ( id serial NOT NULL, codigo_ibge integer NOT NULL, nome_completo text NULL, ano_nascimento integer NOT NULL, data_cadastro timestamp without time zone NOT NULL, CONSTRAINT pk_test_snake_case PRIMARY KEY (id) ); Pessoal fico por aqui e um forte abraço! 😄 #mvpbuzz #mvpbr #mvp #developerssergipe #share #vscode #postgresql #efcore]]></summary></entry><entry><title type="html">LGPD + EF CORE + ValueConverter</title><link href="http://old-blog.ralms.io/ef7/gdpr-efcore-intro/" rel="alternate" type="text/html" title="LGPD + EF CORE + ValueConverter" /><published>2023-07-02T00:00:00-03:00</published><updated>2023-07-02T00:00:00-03:00</updated><id>http://old-blog.ralms.io/ef7/gdpr-efcore-intro</id><content type="html" xml:base="http://old-blog.ralms.io/ef7/gdpr-efcore-intro/"><![CDATA[<p><img src="http://old-blog.ralms.io/assets/images/gdpr/LGPD_EFCORE.png" alt="01" /></p>

<center><strong>Olá tudo bem?!</strong></center>
<hr />

<h2 id="mais-1-artigo-desculpa-estou-de-férias">Mais 1 artigo??? Desculpa estou de férias!!!</h2>
<div class="notice--warning">
Bom, primeiramente o objetivo não é falar sobre LGPD, como conceitos, onde se aplica, como funciona,... nada disso,
apenas mostrar que podemos proteger nossos dados de forma segura e simples usando <b>Entity Framework Core</b>.
<br /><br />
Mas pera aí, você não vai falar nada de LGPD?... tá bom, LGPD é um acrônimo para (<i>Lei Geral de Proteção de Dados Pessoais</i>) que
basicamente o Brasil adotou depois que alguns paises da Europa começaram exigir que o GDPR fosse implementado, para que os dados dos cidadões e sua privacidade pudesse estar segura.<br />
Basicamente de forma muito resumida é isso... antes de criticas observe que falei "BASICAMENTE".<br />
Você pode acessar os links abaixo para obter mais informações:<br />
<a target="_BLANK" href="https://pt.wikipedia.org/wiki/Regulamento_Geral_sobre_a_Prote%C3%A7%C3%A3o_de_Dados" alt="">GDPR</a><br />
<a target="_BLANK" href="https://pt.wikipedia.org/wiki/Lei_Geral_de_Prote%C3%A7%C3%A3o_de_Dados_Pessoais" alt="">LGPD</a>
</div>

<h2 id="cenário">Cenário</h2>
<div style="text-align: justify;">
Imagine que você está usando o <b>EF Core</b> e precisa armazenar informações de algumas propriedas específicas criptografadas em
sua base de dados, para garantir a integridade da informação e que os dados sejam exibidos apenas 
pelo sistema, ou pelo dono da informação, que para nosso exemplo será nossa própria aplicação.
<br /><br />
<pre>
<b>Fulando:</b> Rafael com todo respeito isso é fácil!
<b>Rafael:</b> Tudo bem, só acredito que posso 
        tornar ainda mais fácil.
</pre>
<br />
Bom vamos começar a montar nosso sistema de cadastro de clientes, onde teremos uma classe <b>Cliente</b> com a seguinte estrutura.
</div>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">Cliente</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="kt">int</span> <span class="n">Id</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">Nome</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">Telefone</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">Endereco</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">CPF</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<div style="text-align: justify;">
Agora vamos criar nossa classe de contexto para acessar o banco de dados, basicamente essa é a estrutura da classe:
</div>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="k">public</span> <span class="k">class</span> <span class="nc">DatabaseContext</span> <span class="p">:</span> <span class="n">DbContext</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="n">DbSet</span><span class="p">&lt;</span><span class="n">Cliente</span><span class="p">&gt;</span> <span class="n">Clientes</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>

    <span class="k">protected</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">OnConfiguring</span><span class="p">(</span>
        <span class="n">DbContextOptionsBuilder</span> <span class="n">optionsBuilder</span><span class="p">)</span>
        <span class="p">=&gt;</span> <span class="n">optionsBuilder</span>
            <span class="p">.</span><span class="nf">UseSqlServer</span><span class="p">(</span><span class="s">@"Server=(localdb)\msSqlLocalDB;Integrated Security=True;Database=EFCoreValueConvertion;MultipleActiveResultSets=true;"</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>
<div style="text-align: justify;">
Vamos inserir um cliente em nossa base de dados e fazer uma consulta.
</div>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">Program</span>
<span class="p">{</span>
    <span class="k">static</span> <span class="k">void</span> <span class="nf">Main</span><span class="p">(</span><span class="kt">string</span><span class="p">[]</span> <span class="n">args</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">using</span> <span class="nn">var</span> <span class="n">db</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">DatabaseContext</span><span class="p">();</span>
        <span class="n">db</span><span class="p">.</span><span class="n">Database</span><span class="p">.</span><span class="nf">EnsureCreated</span><span class="p">();</span>

        <span class="n">db</span><span class="p">.</span><span class="n">Clientes</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="k">new</span> <span class="n">Cliente</span>
        <span class="p">{</span>
            <span class="n">Nome</span> <span class="p">=</span> <span class="s">"Rafael Almeida"</span><span class="p">,</span>
            <span class="n">Endereco</span> <span class="p">=</span> <span class="s">"Aqui mesmo"</span><span class="p">,</span>
            <span class="n">Telefone</span> <span class="p">=</span> <span class="s">"7998829XXXX"</span><span class="p">,</span>
            <span class="n">CPF</span> <span class="p">=</span> <span class="s">"123456"</span>
        <span class="p">});</span>

        <span class="n">db</span><span class="p">.</span><span class="nf">SaveChanges</span><span class="p">();</span>

        <span class="kt">var</span> <span class="n">cliente</span> <span class="p">=</span> <span class="n">db</span>
            <span class="p">.</span><span class="n">Clientes</span>
            <span class="p">.</span><span class="nf">AsNoTracking</span><span class="p">()</span>
            <span class="p">.</span><span class="nf">FirstOrDefault</span><span class="p">(</span><span class="n">p</span> <span class="p">=&gt;</span> <span class="n">p</span><span class="p">.</span><span class="n">CPF</span> <span class="p">==</span> <span class="s">"123456"</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="comandos-gerados">Comandos gerados</h2>
<p>Os comandos produzidos pelo <b>EF Core</b> foram esses:<br />
<b>Comando Inserir</b></p>
<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">exec</span> <span class="n">sp_executesql</span> <span class="n">N</span><span class="s1">'SET NOCOUNT ON;
INSERT INTO [Clientes] ([CPF], [Endereco], [Nome], [Telefone])
VALUES (@p0, @p1, @p2, @p3);
SELECT [Id]
FROM [Clientes]
WHERE @@ROWCOUNT = 1 AND [Id] = scope_identity();

'</span><span class="p">,</span><span class="n">N</span><span class="s1">'@p0 nvarchar(4000),@p1 nvarchar(4000),@p2 nvarchar(4000),@p3 nvarchar(4000)'</span><span class="p">,</span>
<span class="o">@</span><span class="n">p0</span><span class="o">=</span><span class="n">N</span><span class="s1">'123456'</span><span class="p">,</span><span class="o">@</span><span class="n">p1</span><span class="o">=</span><span class="n">N</span><span class="s1">'Aqui mesmo'</span><span class="p">,</span><span class="o">@</span><span class="n">p2</span><span class="o">=</span><span class="n">N</span><span class="s1">'Rafael Almeida'</span><span class="p">,</span><span class="o">@</span><span class="n">p3</span><span class="o">=</span><span class="n">N</span><span class="s1">'7998829XXXX'</span>
</code></pre></div></div>
<p><b>Comando Consultar</b></p>
<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">SELECT</span> <span class="n">TOP</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="p">[</span><span class="k">c</span><span class="p">].[</span><span class="n">Id</span><span class="p">],</span> <span class="p">[</span><span class="k">c</span><span class="p">].[</span><span class="n">CPF</span><span class="p">],</span> <span class="p">[</span><span class="k">c</span><span class="p">].[</span><span class="n">Endereco</span><span class="p">],</span> <span class="p">[</span><span class="k">c</span><span class="p">].[</span><span class="n">Nome</span><span class="p">],</span> <span class="p">[</span><span class="k">c</span><span class="p">].[</span><span class="n">Telefone</span><span class="p">]</span>
<span class="k">FROM</span> <span class="p">[</span><span class="n">Clientes</span><span class="p">]</span> <span class="k">AS</span> <span class="p">[</span><span class="k">c</span><span class="p">]</span>
<span class="k">WHERE</span> <span class="p">[</span><span class="k">c</span><span class="p">].[</span><span class="n">CPF</span><span class="p">]</span> <span class="o">=</span> <span class="n">N</span><span class="s1">'123456'</span>
</code></pre></div></div>

<h2 id="protegendo-dados-explícitamente">Protegendo dados explícitamente</h2>
<p>Até aqui tudo normal, nada de novo, então vamos voltar ao assunto de proteger os dados?!<br />
Mas eu gostaria que <b>Telefone e CPF</b>, seja armazenado de forma criptografada, você poderia apenas criar uma função para criptografar os dados no momento que for persistir, e quando consultar descriptografar os dados.<br />
Perfeito, então vejo você fazendo algo assim:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">Program</span>
<span class="p">{</span>
    <span class="k">static</span> <span class="k">void</span> <span class="nf">Main</span><span class="p">(</span><span class="kt">string</span><span class="p">[]</span> <span class="n">args</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">using</span> <span class="nn">var</span> <span class="n">db</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">DatabaseContext</span><span class="p">();</span>
        <span class="n">db</span><span class="p">.</span><span class="n">Database</span><span class="p">.</span><span class="nf">EnsureCreated</span><span class="p">();</span>
        <span class="n">db</span><span class="p">.</span><span class="n">Clientes</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="k">new</span> <span class="n">Cliente</span>
        <span class="p">{</span>
            <span class="n">Nome</span> <span class="p">=</span> <span class="s">"Rafael Almeida"</span><span class="p">,</span>
            <span class="n">Endereco</span> <span class="p">=</span> <span class="s">"Aqui mesmo"</span><span class="p">,</span>
            <span class="n">Telefone</span> <span class="p">=</span> <span class="nf">LockView</span><span class="p">(</span><span class="s">"7998829XXXX"</span><span class="p">),</span> <span class="c1">//Criptografando</span>
            <span class="n">CPF</span> <span class="p">=</span> <span class="nf">LockView</span><span class="p">(</span><span class="s">"123456"</span><span class="p">)</span> <span class="c1">// Criptografando</span>
        <span class="p">});</span>

        <span class="n">db</span><span class="p">.</span><span class="nf">SaveChanges</span><span class="p">();</span>

        <span class="kt">var</span> <span class="n">cliente</span> <span class="p">=</span> <span class="n">db</span>
            <span class="p">.</span><span class="n">Clientes</span>
            <span class="p">.</span><span class="nf">AsNoTracking</span><span class="p">()</span>
            <span class="p">.</span><span class="nf">FirstOrDefault</span><span class="p">(</span><span class="n">p</span> <span class="p">=&gt;</span> <span class="n">p</span><span class="p">.</span><span class="n">CPF</span> <span class="p">==</span> <span class="nf">LockView</span><span class="p">(</span><span class="s">"123456"</span><span class="p">));</span>

        <span class="kt">var</span> <span class="n">cpf</span> <span class="p">=</span> <span class="nf">UnLockView</span><span class="p">(</span><span class="n">cliente</span><span class="p">.</span><span class="n">CPF</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">static</span> <span class="kt">string</span> <span class="nf">LockView</span><span class="p">(</span><span class="kt">string</span> <span class="n">texto</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">using</span> <span class="nn">var</span> <span class="n">hashProvider</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">MD5CryptoServiceProvider</span><span class="p">();</span>
        <span class="kt">var</span> <span class="n">encriptar</span> <span class="p">=</span> <span class="k">new</span> <span class="n">TripleDESCryptoServiceProvider</span>
        <span class="p">{</span>
            <span class="n">Mode</span> <span class="p">=</span> <span class="n">CipherMode</span><span class="p">.</span><span class="n">ECB</span><span class="p">,</span>
            <span class="n">Key</span> <span class="p">=</span> <span class="n">hashProvider</span><span class="p">.</span><span class="nf">ComputeHash</span><span class="p">(</span><span class="n">_chave</span><span class="p">),</span>
            <span class="n">Padding</span> <span class="p">=</span> <span class="n">PaddingMode</span><span class="p">.</span><span class="n">PKCS7</span>
        <span class="p">};</span>

        <span class="k">using</span> <span class="nn">var</span> <span class="n">transforme</span> <span class="p">=</span> <span class="n">encriptar</span><span class="p">.</span><span class="nf">CreateEncryptor</span><span class="p">();</span>
        <span class="kt">var</span> <span class="n">dados</span> <span class="p">=</span> <span class="n">Encoding</span><span class="p">.</span><span class="n">UTF8</span><span class="p">.</span><span class="nf">GetBytes</span><span class="p">(</span><span class="n">texto</span><span class="p">);</span>
        <span class="k">return</span> <span class="n">Convert</span><span class="p">.</span><span class="nf">ToBase64String</span><span class="p">(</span><span class="n">transforme</span><span class="p">.</span><span class="nf">TransformFinalBlock</span><span class="p">(</span><span class="n">dados</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="n">dados</span><span class="p">.</span><span class="n">Length</span><span class="p">));</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="delegando-responsabilidade">Delegando responsabilidade</h2>
<p>Funciona perfeitamente, não é a melhor maneira de fazer, então podemos melhorar isso e delegar a responsabilidade para o <b>EF Core</b>, vamos criar um atributo e extrair funcionalidades que o <b>EF Core</b> nos
proporciona, nesse caso primeiramente vamos criar nosso atributo <b>SensitiveData</b>.</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">[</span><span class="nf">AttributeUsage</span><span class="p">(</span><span class="n">AttributeTargets</span><span class="p">.</span><span class="n">Property</span><span class="p">,</span> <span class="n">Inherited</span> <span class="p">=</span> <span class="k">false</span><span class="p">,</span> <span class="n">AllowMultiple</span> <span class="p">=</span> <span class="k">false</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">sealed</span> <span class="k">class</span> <span class="nc">SensitiveDataAttribute</span> <span class="p">:</span> <span class="n">Attribute</span>
<span class="p">{</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Agora vamos adicionar o atributo em todas propriedades que queremos que o <b>EF Core</b> fique responsável pelo trabalho pesado, de armazenar e ler os dados sensíveis.</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">Cliente</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="kt">int</span> <span class="n">Id</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">Nome</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="p">[</span><span class="n">SensitiveData</span><span class="p">]</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">Telefone</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">Endereco</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="p">[</span><span class="n">SensitiveData</span><span class="p">]</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">CPF</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<div style="text-align: justify;">
Agora vamos criar uma classe customizada para ficar responsável pela conversão dos valores que serão persistidos e lidos de nossa base de dados,
a partir do <b>EF Core 2.1</b> temos uma nova funcionalidade que basicamente nos fornece uma forma na qual podemos manipular o dado antes de ser persistido e quando for lido também, 
essa funcionalidade se chama <b>ValueConverter</b>, em breve irei fazer um artigo falando mais sobre ela, por enquanto vamos focar aqui, e nossa classe customizada ficou da 
seguinte forma com 2 metódos, para critografar e descriptografar os dados, o que fiz foi criar um classe que herda da classe <b>ValueConverter</b> alguns comportamentos, onde em nosso construtor eu passo 
a expressão que eu quero utilizar para persitir e ler dados.
</div>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">DataProtectionConverter</span> <span class="p">:</span> <span class="n">ValueConverter</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">,</span> <span class="kt">string</span><span class="p">&gt;</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">static</span> <span class="kt">byte</span><span class="p">[]</span> <span class="n">_chave</span> <span class="p">=</span> <span class="n">Encoding</span><span class="p">.</span><span class="n">UTF8</span><span class="p">.</span><span class="nf">GetBytes</span><span class="p">(</span><span class="s">"#lgpd+ef"</span><span class="p">);</span>

    <span class="k">public</span> <span class="nf">DataProtectionConverter</span><span class="p">()</span>
        <span class="p">:</span> <span class="k">base</span><span class="p">(</span><span class="n">_convertTo</span><span class="p">,</span> <span class="n">_convertFrom</span><span class="p">,</span> <span class="k">default</span><span class="p">)</span>
    <span class="p">{</span>
    <span class="p">}</span>

    <span class="k">static</span> <span class="n">Expression</span><span class="p">&lt;</span><span class="n">Func</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">,</span> <span class="kt">string</span><span class="p">&gt;&gt;</span> <span class="n">_convertTo</span> <span class="p">=</span> <span class="n">x</span> <span class="p">=&gt;</span> <span class="nf">LockView</span><span class="p">(</span><span class="n">x</span><span class="p">);</span>
    <span class="k">static</span> <span class="n">Expression</span><span class="p">&lt;</span><span class="n">Func</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">,</span> <span class="kt">string</span><span class="p">&gt;&gt;</span> <span class="n">_convertFrom</span> <span class="p">=</span> <span class="n">x</span> <span class="p">=&gt;</span> <span class="nf">UnLockView</span><span class="p">(</span><span class="n">x</span><span class="p">);</span>

    <span class="k">static</span> <span class="kt">string</span> <span class="nf">LockView</span><span class="p">(</span><span class="kt">string</span> <span class="n">texto</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">using</span> <span class="nn">var</span> <span class="n">hashProvider</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">MD5CryptoServiceProvider</span><span class="p">();</span>
        <span class="kt">var</span> <span class="n">encriptar</span> <span class="p">=</span> <span class="k">new</span> <span class="n">TripleDESCryptoServiceProvider</span>
        <span class="p">{</span>
            <span class="n">Mode</span> <span class="p">=</span> <span class="n">CipherMode</span><span class="p">.</span><span class="n">ECB</span><span class="p">,</span>
            <span class="n">Key</span> <span class="p">=</span> <span class="n">hashProvider</span><span class="p">.</span><span class="nf">ComputeHash</span><span class="p">(</span><span class="n">_chave</span><span class="p">),</span>
            <span class="n">Padding</span> <span class="p">=</span> <span class="n">PaddingMode</span><span class="p">.</span><span class="n">PKCS7</span>
        <span class="p">};</span>

        <span class="k">using</span> <span class="nn">var</span> <span class="n">transforme</span> <span class="p">=</span> <span class="n">encriptar</span><span class="p">.</span><span class="nf">CreateEncryptor</span><span class="p">();</span>
        <span class="kt">var</span> <span class="n">dados</span> <span class="p">=</span> <span class="n">Encoding</span><span class="p">.</span><span class="n">UTF8</span><span class="p">.</span><span class="nf">GetBytes</span><span class="p">(</span><span class="n">texto</span><span class="p">);</span>
        <span class="k">return</span> <span class="n">Convert</span><span class="p">.</span><span class="nf">ToBase64String</span><span class="p">(</span><span class="n">transforme</span><span class="p">.</span><span class="nf">TransformFinalBlock</span><span class="p">(</span><span class="n">dados</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="n">dados</span><span class="p">.</span><span class="n">Length</span><span class="p">));</span>
    <span class="p">}</span>

    <span class="k">static</span> <span class="kt">string</span> <span class="nf">UnLockView</span><span class="p">(</span><span class="kt">string</span> <span class="n">texto</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">using</span> <span class="nn">var</span> <span class="n">hashProvider</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">MD5CryptoServiceProvider</span><span class="p">();</span>
        <span class="kt">var</span> <span class="n">descriptografar</span> <span class="p">=</span> <span class="k">new</span> <span class="n">TripleDESCryptoServiceProvider</span>
        <span class="p">{</span>
            <span class="n">Mode</span> <span class="p">=</span> <span class="n">CipherMode</span><span class="p">.</span><span class="n">ECB</span><span class="p">,</span>
            <span class="n">Key</span> <span class="p">=</span> <span class="n">hashProvider</span><span class="p">.</span><span class="nf">ComputeHash</span><span class="p">(</span><span class="n">_chave</span><span class="p">),</span>
            <span class="n">Padding</span> <span class="p">=</span> <span class="n">PaddingMode</span><span class="p">.</span><span class="n">PKCS7</span>
        <span class="p">};</span>

        <span class="k">using</span> <span class="nn">var</span> <span class="n">transforme</span> <span class="p">=</span> <span class="n">descriptografar</span><span class="p">.</span><span class="nf">CreateDecryptor</span><span class="p">();</span>
        <span class="kt">var</span> <span class="n">dados</span> <span class="p">=</span> <span class="n">Convert</span><span class="p">.</span><span class="nf">FromBase64String</span><span class="p">(</span><span class="n">texto</span><span class="p">.</span><span class="nf">Replace</span><span class="p">(</span><span class="s">" "</span><span class="p">,</span> <span class="s">"+"</span><span class="p">));</span>
        <span class="k">return</span> <span class="n">Encoding</span><span class="p">.</span><span class="n">UTF8</span><span class="p">.</span><span class="nf">GetString</span><span class="p">(</span><span class="n">transforme</span><span class="p">.</span><span class="nf">TransformFinalBlock</span><span class="p">(</span><span class="n">dados</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="n">dados</span><span class="p">.</span><span class="n">Length</span><span class="p">));</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<div style="text-align: justify;">
Classe criada, agora vamos ajustar nosso <b>DatabaseContext</b> da seguinte forma:
</div>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">DatabaseContext</span> <span class="p">:</span> <span class="n">DbContext</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="n">DbSet</span><span class="p">&lt;</span><span class="n">Cliente</span><span class="p">&gt;</span> <span class="n">Clientes</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>

    <span class="k">protected</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">OnConfiguring</span><span class="p">(</span>
        <span class="n">DbContextOptionsBuilder</span> <span class="n">optionsBuilder</span><span class="p">)</span>
        <span class="p">=&gt;</span> <span class="n">optionsBuilder</span>
            <span class="p">.</span><span class="nf">UseSqlServer</span><span class="p">(</span>
                <span class="s">@"Server=(localdb)\msSqlLocalDB;Integrated Security=True; Database=EFCoreValueConvertion; MultipleActiveResultSets=true;"</span>
            <span class="p">);</span>

    
    <span class="k">protected</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">OnModelCreating</span><span class="p">(</span><span class="n">ModelBuilder</span> <span class="n">modelBuilder</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="c1">// Selecionar todas propriedades que tem a anotação SensitiveData</span>
        <span class="c1">// e aplicar o conversor de valores para o que criamos.</span>
        <span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">entity</span> <span class="k">in</span> <span class="n">modelBuilder</span><span class="p">.</span><span class="n">Model</span><span class="p">.</span><span class="nf">GetEntityTypes</span><span class="p">())</span>
        <span class="p">{</span>
            <span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">property</span> <span class="k">in</span> <span class="n">entity</span><span class="p">.</span><span class="nf">GetProperties</span><span class="p">())</span>
            <span class="p">{</span>
                <span class="kt">var</span> <span class="n">attributes</span> <span class="p">=</span> <span class="n">property</span>
                    <span class="p">.</span><span class="n">PropertyInfo</span>
                    <span class="p">.</span><span class="nf">GetCustomAttributes</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">SensitiveDataAttribute</span><span class="p">),</span> <span class="k">false</span><span class="p">);</span>

                <span class="k">if</span> <span class="p">(</span><span class="n">attributes</span><span class="p">.</span><span class="n">Length</span> <span class="p">&gt;</span> <span class="m">0</span><span class="p">)</span>
                <span class="p">{</span>
                    <span class="n">property</span><span class="p">.</span><span class="nf">SetValueConverter</span><span class="p">(</span><span class="k">new</span> <span class="nf">DataProtectionConverter</span><span class="p">());</span>
                <span class="p">}</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="código-final">Código final</h2>
<p>Agora como você pode ver não iremos precisar mais ficar criptografando explicitamente as informações, nosso exemplo completo ficou assim:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">Program</span>
<span class="p">{</span>
    <span class="k">static</span> <span class="k">void</span> <span class="nf">Main</span><span class="p">(</span><span class="kt">string</span><span class="p">[]</span> <span class="n">args</span><span class="p">)</span>
    <span class="p">{</span>

        <span class="k">using</span> <span class="nn">var</span> <span class="n">db</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">DatabaseContext</span><span class="p">();</span>
        <span class="n">db</span><span class="p">.</span><span class="n">Database</span><span class="p">.</span><span class="nf">EnsureCreated</span><span class="p">();</span>
        <span class="n">db</span><span class="p">.</span><span class="n">Clientes</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="k">new</span> <span class="n">Cliente</span>
        <span class="p">{</span>
            <span class="n">Nome</span> <span class="p">=</span> <span class="s">"Rafael Almeida"</span><span class="p">,</span>
            <span class="n">Endereco</span> <span class="p">=</span> <span class="s">"Aqui mesmo"</span><span class="p">,</span>
            <span class="n">Telefone</span> <span class="p">=</span> <span class="s">"7998829XXXX"</span><span class="p">,</span>
            <span class="n">CPF</span> <span class="p">=</span> <span class="s">"123456"</span>
        <span class="p">});</span>

        <span class="n">db</span><span class="p">.</span><span class="nf">SaveChanges</span><span class="p">();</span>

        <span class="kt">var</span> <span class="n">cliente</span> <span class="p">=</span> <span class="n">db</span><span class="p">.</span><span class="n">Clientes</span><span class="p">.</span><span class="nf">AsNoTracking</span><span class="p">().</span><span class="nf">FirstOrDefault</span><span class="p">(</span><span class="n">p</span> <span class="p">=&gt;</span> <span class="n">p</span><span class="p">.</span><span class="n">CPF</span> <span class="p">==</span> <span class="s">"123456"</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="c1">// SensitiveDataAttribute</span>
<span class="p">[</span><span class="nf">AttributeUsage</span><span class="p">(</span><span class="n">AttributeTargets</span><span class="p">.</span><span class="n">Property</span><span class="p">,</span> <span class="n">Inherited</span> <span class="p">=</span> <span class="k">false</span><span class="p">,</span> <span class="n">AllowMultiple</span> <span class="p">=</span> <span class="k">false</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">sealed</span> <span class="k">class</span> <span class="nc">SensitiveDataAttribute</span> <span class="p">:</span> <span class="n">Attribute</span>
<span class="p">{</span>
<span class="p">}</span>

<span class="c1">// Cliente</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">Cliente</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="kt">int</span> <span class="n">Id</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">Nome</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="p">[</span><span class="n">SensitiveData</span><span class="p">]</span>                     <span class="c1">// SensitiveData</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">Telefone</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">Endereco</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="p">[</span><span class="n">SensitiveData</span><span class="p">]</span>                     <span class="c1">// SensitiveData</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">CPF</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>


<span class="c1">// DatabaseContext</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">DatabaseContext</span> <span class="p">:</span> <span class="n">DbContext</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="n">DbSet</span><span class="p">&lt;</span><span class="n">Cliente</span><span class="p">&gt;</span> <span class="n">Clientes</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>

    <span class="k">protected</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">OnConfiguring</span><span class="p">(</span>
        <span class="n">DbContextOptionsBuilder</span> <span class="n">optionsBuilder</span><span class="p">)</span>
        <span class="p">=&gt;</span> <span class="n">optionsBuilder</span>
            <span class="p">.</span><span class="nf">UseSqlServer</span><span class="p">(</span>
                <span class="s">@"Server=(localdb)\msSqlLocalDB;Integrated Security=True; Database=EFCoreValueConvertion; MultipleActiveResultSets=true;"</span>
            <span class="p">);</span>

    <span class="k">protected</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">OnModelCreating</span><span class="p">(</span><span class="n">ModelBuilder</span> <span class="n">modelBuilder</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">entity</span> <span class="k">in</span> <span class="n">modelBuilder</span><span class="p">.</span><span class="n">Model</span><span class="p">.</span><span class="nf">GetEntityTypes</span><span class="p">())</span>
        <span class="p">{</span>
            <span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">property</span> <span class="k">in</span> <span class="n">entity</span><span class="p">.</span><span class="nf">GetProperties</span><span class="p">())</span>
            <span class="p">{</span>
                <span class="kt">var</span> <span class="n">attributes</span> <span class="p">=</span> <span class="n">property</span>
                    <span class="p">.</span><span class="n">PropertyInfo</span>
                    <span class="p">.</span><span class="nf">GetCustomAttributes</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">SensitiveDataAttribute</span><span class="p">),</span> <span class="k">false</span><span class="p">);</span>

                <span class="k">if</span> <span class="p">(</span><span class="n">attributes</span><span class="p">.</span><span class="n">Length</span> <span class="p">&gt;</span> <span class="m">0</span><span class="p">)</span>
                <span class="p">{</span>
                    <span class="n">property</span><span class="p">.</span><span class="nf">SetValueConverter</span><span class="p">(</span><span class="k">new</span> <span class="nf">DataProtectionConverter</span><span class="p">());</span>
                <span class="p">}</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="c1">// DataProtectionConverter</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">DataProtectionConverter</span> <span class="p">:</span> <span class="n">ValueConverter</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">,</span> <span class="kt">string</span><span class="p">&gt;</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">static</span> <span class="kt">byte</span><span class="p">[]</span> <span class="n">_chave</span> <span class="p">=</span> <span class="n">Encoding</span><span class="p">.</span><span class="n">UTF8</span><span class="p">.</span><span class="nf">GetBytes</span><span class="p">(</span><span class="s">"#lgpd+ef"</span><span class="p">);</span>

    <span class="k">public</span> <span class="nf">DataProtectionConverter</span><span class="p">()</span>
        <span class="p">:</span> <span class="k">base</span><span class="p">(</span><span class="n">_convertTo</span><span class="p">,</span> <span class="n">_convertFrom</span><span class="p">,</span> <span class="k">default</span><span class="p">)</span>
    <span class="p">{</span>
    <span class="p">}</span>

    <span class="k">private</span> <span class="k">static</span> <span class="n">Expression</span><span class="p">&lt;</span><span class="n">Func</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">,</span> <span class="kt">string</span><span class="p">&gt;&gt;</span> <span class="n">_convertTo</span> <span class="p">=</span> <span class="n">x</span> <span class="p">=&gt;</span> <span class="nf">LockView</span><span class="p">(</span><span class="n">x</span><span class="p">);</span>
    <span class="k">private</span> <span class="k">static</span> <span class="n">Expression</span><span class="p">&lt;</span><span class="n">Func</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">,</span> <span class="kt">string</span><span class="p">&gt;&gt;</span> <span class="n">_convertFrom</span> <span class="p">=</span> <span class="n">x</span> <span class="p">=&gt;</span> <span class="nf">UnLockView</span><span class="p">(</span><span class="n">x</span><span class="p">);</span>

    <span class="k">static</span> <span class="kt">string</span> <span class="nf">LockView</span><span class="p">(</span><span class="kt">string</span> <span class="n">texto</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">using</span> <span class="nn">var</span> <span class="n">hashProvider</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">MD5CryptoServiceProvider</span><span class="p">();</span>
        <span class="kt">var</span> <span class="n">encriptar</span> <span class="p">=</span> <span class="k">new</span> <span class="n">TripleDESCryptoServiceProvider</span>
        <span class="p">{</span>
            <span class="n">Mode</span> <span class="p">=</span> <span class="n">CipherMode</span><span class="p">.</span><span class="n">ECB</span><span class="p">,</span>
            <span class="n">Key</span> <span class="p">=</span> <span class="n">hashProvider</span><span class="p">.</span><span class="nf">ComputeHash</span><span class="p">(</span><span class="n">_chave</span><span class="p">),</span>
            <span class="n">Padding</span> <span class="p">=</span> <span class="n">PaddingMode</span><span class="p">.</span><span class="n">PKCS7</span>
        <span class="p">};</span>

        <span class="k">using</span> <span class="nn">var</span> <span class="n">transforme</span> <span class="p">=</span> <span class="n">encriptar</span><span class="p">.</span><span class="nf">CreateEncryptor</span><span class="p">();</span>
        <span class="kt">var</span> <span class="n">dados</span> <span class="p">=</span> <span class="n">Encoding</span><span class="p">.</span><span class="n">UTF8</span><span class="p">.</span><span class="nf">GetBytes</span><span class="p">(</span><span class="n">texto</span><span class="p">);</span>
        <span class="k">return</span> <span class="n">Convert</span><span class="p">.</span><span class="nf">ToBase64String</span><span class="p">(</span><span class="n">transforme</span><span class="p">.</span><span class="nf">TransformFinalBlock</span><span class="p">(</span><span class="n">dados</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="n">dados</span><span class="p">.</span><span class="n">Length</span><span class="p">));</span>
    <span class="p">}</span>

    <span class="k">static</span> <span class="kt">string</span> <span class="nf">UnLockView</span><span class="p">(</span><span class="kt">string</span> <span class="n">texto</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">using</span> <span class="nn">var</span> <span class="n">hashProvider</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">MD5CryptoServiceProvider</span><span class="p">();</span>
        <span class="kt">var</span> <span class="n">descriptografar</span> <span class="p">=</span> <span class="k">new</span> <span class="n">TripleDESCryptoServiceProvider</span>
        <span class="p">{</span>
            <span class="n">Mode</span> <span class="p">=</span> <span class="n">CipherMode</span><span class="p">.</span><span class="n">ECB</span><span class="p">,</span>
            <span class="n">Key</span> <span class="p">=</span> <span class="n">hashProvider</span><span class="p">.</span><span class="nf">ComputeHash</span><span class="p">(</span><span class="n">_chave</span><span class="p">),</span>
            <span class="n">Padding</span> <span class="p">=</span> <span class="n">PaddingMode</span><span class="p">.</span><span class="n">PKCS7</span>
        <span class="p">};</span>

        <span class="k">using</span> <span class="nn">var</span> <span class="n">transforme</span> <span class="p">=</span> <span class="n">descriptografar</span><span class="p">.</span><span class="nf">CreateDecryptor</span><span class="p">();</span>
        <span class="kt">var</span> <span class="n">dados</span> <span class="p">=</span> <span class="n">Convert</span><span class="p">.</span><span class="nf">FromBase64String</span><span class="p">(</span><span class="n">texto</span><span class="p">.</span><span class="nf">Replace</span><span class="p">(</span><span class="s">" "</span><span class="p">,</span> <span class="s">"+"</span><span class="p">));</span>
        <span class="k">return</span> <span class="n">Encoding</span><span class="p">.</span><span class="n">UTF8</span><span class="p">.</span><span class="nf">GetString</span><span class="p">(</span><span class="n">transforme</span><span class="p">.</span><span class="nf">TransformFinalBlock</span><span class="p">(</span><span class="n">dados</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="n">dados</span><span class="p">.</span><span class="n">Length</span><span class="p">));</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="output-sql">Output SQL</h2>
<p>Os comandos produzidos ficaram assim:<br />
<b>Comando Inserir</b></p>
<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">exec</span> <span class="n">sp_executesql</span> <span class="n">N</span><span class="s1">'SET NOCOUNT ON;
INSERT INTO [Clientes] ([CPF], [Endereco], [Nome], [Telefone])
VALUES (@p0, @p1, @p2, @p3);
SELECT [Id]
FROM [Clientes]
WHERE @@ROWCOUNT = 1 AND [Id] = scope_identity();

'</span><span class="p">,</span><span class="n">N</span><span class="s1">'@p0 nvarchar(4000),@p1 nvarchar(4000),@p2 nvarchar(4000),@p3 nvarchar(4000)'</span><span class="p">,</span>
<span class="o">@</span><span class="n">p0</span><span class="o">=</span><span class="n">N</span><span class="s1">'kOI/e7VQZhs='</span><span class="p">,</span> <span class="c1">-- Criptografado</span>
<span class="o">@</span><span class="n">p1</span><span class="o">=</span><span class="n">N</span><span class="s1">'Aqui mesmo'</span><span class="p">,</span><span class="o">@</span><span class="n">p2</span><span class="o">=</span><span class="n">N</span><span class="s1">'Rafael Almeida'</span><span class="p">,</span>
<span class="o">@</span><span class="n">p3</span><span class="o">=</span><span class="n">N</span><span class="s1">'T2wQKyR8w28fKOgBXp0ytg=='</span>    <span class="c1">-- Criptografado</span>
</code></pre></div></div>
<p><b>Comando Consultar</b></p>
<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">SELECT</span> <span class="n">TOP</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="p">[</span><span class="k">c</span><span class="p">].[</span><span class="n">Id</span><span class="p">],</span> <span class="p">[</span><span class="k">c</span><span class="p">].[</span><span class="n">CPF</span><span class="p">],</span> <span class="p">[</span><span class="k">c</span><span class="p">].[</span><span class="n">Endereco</span><span class="p">],</span> <span class="p">[</span><span class="k">c</span><span class="p">].[</span><span class="n">Nome</span><span class="p">],</span> <span class="p">[</span><span class="k">c</span><span class="p">].[</span><span class="n">Telefone</span><span class="p">]</span>
<span class="k">FROM</span> <span class="p">[</span><span class="n">Clientes</span><span class="p">]</span> <span class="k">AS</span> <span class="p">[</span><span class="k">c</span><span class="p">]</span>
<span class="k">WHERE</span> <span class="p">[</span><span class="k">c</span><span class="p">].[</span><span class="n">CPF</span><span class="p">]</span> <span class="o">=</span> <span class="n">N</span><span class="s1">'kOI/e7VQZhs='</span>
</code></pre></div></div>
<p><img src="http://old-blog.ralms.io/assets/images/gdpr/consulta.png" alt="01" /></p>

<h2 id="observações">Observações</h2>
<div class="notice--warning">
Alguns banco de dados já fornecem criptografia de ponta-a-ponta, um banco de dados é apenas uma das ferramentas que podemos usar para que possamos estar em conformidade com LGPD/GDPR, uma dica é fique de olho 
na profissão de DPO (<i>Data Protection Officer</i>), será uma profissão que terá muitas vagas para os próximos anos, muitas empresas vão precisar desse profissional.
</div>

<h2 id="twitter">Twitter</h2>
<div class="notice--info">
 Fico por aqui! 😄 <br />
 Me siga no twitter: <a alt="" href="https://twitter.com/RalmsDeveloper">@ralmsdeveloper</a><br />
</div>

<p><br /></p>]]></content><author><name>Rafael Almeida</name><email>ralms@ralms.net</email></author><category term="EF7" /><summary type="html"><![CDATA[Olá tudo bem?! Mais 1 artigo??? Desculpa estou de férias!!! Bom, primeiramente o objetivo não é falar sobre LGPD, como conceitos, onde se aplica, como funciona,... nada disso, apenas mostrar que podemos proteger nossos dados de forma segura e simples usando Entity Framework Core. Mas pera aí, você não vai falar nada de LGPD?... tá bom, LGPD é um acrônimo para (Lei Geral de Proteção de Dados Pessoais) que basicamente o Brasil adotou depois que alguns paises da Europa começaram exigir que o GDPR fosse implementado, para que os dados dos cidadões e sua privacidade pudesse estar segura. Basicamente de forma muito resumida é isso... antes de criticas observe que falei "BASICAMENTE". Você pode acessar os links abaixo para obter mais informações: GDPR LGPD Cenário Imagine que você está usando o EF Core e precisa armazenar informações de algumas propriedas específicas criptografadas em sua base de dados, para garantir a integridade da informação e que os dados sejam exibidos apenas pelo sistema, ou pelo dono da informação, que para nosso exemplo será nossa própria aplicação. Fulando: Rafael com todo respeito isso é fácil! Rafael: Tudo bem, só acredito que posso tornar ainda mais fácil. Bom vamos começar a montar nosso sistema de cadastro de clientes, onde teremos uma classe Cliente com a seguinte estrutura. public class Cliente { public int Id { get; set; } public string Nome { get; set; } public string Telefone { get; set; } public string Endereco { get; set; } public string CPF { get; set; } } Agora vamos criar nossa classe de contexto para acessar o banco de dados, basicamente essa é a estrutura da classe: public class DatabaseContext : DbContext { public DbSet&lt;Cliente&gt; Clientes { get; set; } protected override void OnConfiguring( DbContextOptionsBuilder optionsBuilder) =&gt; optionsBuilder .UseSqlServer(@"Server=(localdb)\msSqlLocalDB;Integrated Security=True;Database=EFCoreValueConvertion;MultipleActiveResultSets=true;"); } Vamos inserir um cliente em nossa base de dados e fazer uma consulta. public class Program { static void Main(string[] args) { using var db = new DatabaseContext(); db.Database.EnsureCreated(); db.Clientes.Add(new Cliente { Nome = "Rafael Almeida", Endereco = "Aqui mesmo", Telefone = "7998829XXXX", CPF = "123456" }); db.SaveChanges(); var cliente = db .Clientes .AsNoTracking() .FirstOrDefault(p =&gt; p.CPF == "123456"); } } Comandos gerados Os comandos produzidos pelo EF Core foram esses: Comando Inserir exec sp_executesql N'SET NOCOUNT ON; INSERT INTO [Clientes] ([CPF], [Endereco], [Nome], [Telefone]) VALUES (@p0, @p1, @p2, @p3); SELECT [Id] FROM [Clientes] WHERE @@ROWCOUNT = 1 AND [Id] = scope_identity(); ',N'@p0 nvarchar(4000),@p1 nvarchar(4000),@p2 nvarchar(4000),@p3 nvarchar(4000)', @p0=N'123456',@p1=N'Aqui mesmo',@p2=N'Rafael Almeida',@p3=N'7998829XXXX' Comando Consultar SELECT TOP(1) [c].[Id], [c].[CPF], [c].[Endereco], [c].[Nome], [c].[Telefone] FROM [Clientes] AS [c] WHERE [c].[CPF] = N'123456' Protegendo dados explícitamente Até aqui tudo normal, nada de novo, então vamos voltar ao assunto de proteger os dados?! Mas eu gostaria que Telefone e CPF, seja armazenado de forma criptografada, você poderia apenas criar uma função para criptografar os dados no momento que for persistir, e quando consultar descriptografar os dados. Perfeito, então vejo você fazendo algo assim: public class Program { static void Main(string[] args) { using var db = new DatabaseContext(); db.Database.EnsureCreated(); db.Clientes.Add(new Cliente { Nome = "Rafael Almeida", Endereco = "Aqui mesmo", Telefone = LockView("7998829XXXX"), //Criptografando CPF = LockView("123456") // Criptografando }); db.SaveChanges(); var cliente = db .Clientes .AsNoTracking() .FirstOrDefault(p =&gt; p.CPF == LockView("123456")); var cpf = UnLockView(cliente.CPF); } static string LockView(string texto) { using var hashProvider = new MD5CryptoServiceProvider(); var encriptar = new TripleDESCryptoServiceProvider { Mode = CipherMode.ECB, Key = hashProvider.ComputeHash(_chave), Padding = PaddingMode.PKCS7 }; using var transforme = encriptar.CreateEncryptor(); var dados = Encoding.UTF8.GetBytes(texto); return Convert.ToBase64String(transforme.TransformFinalBlock(dados, 0, dados.Length)); } } Delegando responsabilidade Funciona perfeitamente, não é a melhor maneira de fazer, então podemos melhorar isso e delegar a responsabilidade para o EF Core, vamos criar um atributo e extrair funcionalidades que o EF Core nos proporciona, nesse caso primeiramente vamos criar nosso atributo SensitiveData. [AttributeUsage(AttributeTargets.Property, Inherited = false, AllowMultiple = false)] public sealed class SensitiveDataAttribute : Attribute { } Agora vamos adicionar o atributo em todas propriedades que queremos que o EF Core fique responsável pelo trabalho pesado, de armazenar e ler os dados sensíveis. public class Cliente { public int Id { get; set; } public string Nome { get; set; } [SensitiveData] public string Telefone { get; set; } public string Endereco { get; set; } [SensitiveData] public string CPF { get; set; } } Agora vamos criar uma classe customizada para ficar responsável pela conversão dos valores que serão persistidos e lidos de nossa base de dados, a partir do EF Core 2.1 temos uma nova funcionalidade que basicamente nos fornece uma forma na qual podemos manipular o dado antes de ser persistido e quando for lido também, essa funcionalidade se chama ValueConverter, em breve irei fazer um artigo falando mais sobre ela, por enquanto vamos focar aqui, e nossa classe customizada ficou da seguinte forma com 2 metódos, para critografar e descriptografar os dados, o que fiz foi criar um classe que herda da classe ValueConverter alguns comportamentos, onde em nosso construtor eu passo a expressão que eu quero utilizar para persitir e ler dados. public class DataProtectionConverter : ValueConverter&lt;string, string&gt; { private static byte[] _chave = Encoding.UTF8.GetBytes("#lgpd+ef"); public DataProtectionConverter() : base(_convertTo, _convertFrom, default) { } static Expression&lt;Func&lt;string, string&gt;&gt; _convertTo = x =&gt; LockView(x); static Expression&lt;Func&lt;string, string&gt;&gt; _convertFrom = x =&gt; UnLockView(x); static string LockView(string texto) { using var hashProvider = new MD5CryptoServiceProvider(); var encriptar = new TripleDESCryptoServiceProvider { Mode = CipherMode.ECB, Key = hashProvider.ComputeHash(_chave), Padding = PaddingMode.PKCS7 }; using var transforme = encriptar.CreateEncryptor(); var dados = Encoding.UTF8.GetBytes(texto); return Convert.ToBase64String(transforme.TransformFinalBlock(dados, 0, dados.Length)); } static string UnLockView(string texto) { using var hashProvider = new MD5CryptoServiceProvider(); var descriptografar = new TripleDESCryptoServiceProvider { Mode = CipherMode.ECB, Key = hashProvider.ComputeHash(_chave), Padding = PaddingMode.PKCS7 }; using var transforme = descriptografar.CreateDecryptor(); var dados = Convert.FromBase64String(texto.Replace(" ", "+")); return Encoding.UTF8.GetString(transforme.TransformFinalBlock(dados, 0, dados.Length)); } } Classe criada, agora vamos ajustar nosso DatabaseContext da seguinte forma: public class DatabaseContext : DbContext { public DbSet&lt;Cliente&gt; Clientes { get; set; } protected override void OnConfiguring( DbContextOptionsBuilder optionsBuilder) =&gt; optionsBuilder .UseSqlServer( @"Server=(localdb)\msSqlLocalDB;Integrated Security=True; Database=EFCoreValueConvertion; MultipleActiveResultSets=true;" ); protected override void OnModelCreating(ModelBuilder modelBuilder) { // Selecionar todas propriedades que tem a anotação SensitiveData // e aplicar o conversor de valores para o que criamos. foreach (var entity in modelBuilder.Model.GetEntityTypes()) { foreach (var property in entity.GetProperties()) { var attributes = property .PropertyInfo .GetCustomAttributes(typeof(SensitiveDataAttribute), false); if (attributes.Length &gt; 0) { property.SetValueConverter(new DataProtectionConverter()); } } } } } Código final Agora como você pode ver não iremos precisar mais ficar criptografando explicitamente as informações, nosso exemplo completo ficou assim: public class Program { static void Main(string[] args) { using var db = new DatabaseContext(); db.Database.EnsureCreated(); db.Clientes.Add(new Cliente { Nome = "Rafael Almeida", Endereco = "Aqui mesmo", Telefone = "7998829XXXX", CPF = "123456" }); db.SaveChanges(); var cliente = db.Clientes.AsNoTracking().FirstOrDefault(p =&gt; p.CPF == "123456"); } } // SensitiveDataAttribute [AttributeUsage(AttributeTargets.Property, Inherited = false, AllowMultiple = false)] public sealed class SensitiveDataAttribute : Attribute { } // Cliente public class Cliente { public int Id { get; set; } public string Nome { get; set; } [SensitiveData] // SensitiveData public string Telefone { get; set; } public string Endereco { get; set; } [SensitiveData] // SensitiveData public string CPF { get; set; } } // DatabaseContext public class DatabaseContext : DbContext { public DbSet&lt;Cliente&gt; Clientes { get; set; } protected override void OnConfiguring( DbContextOptionsBuilder optionsBuilder) =&gt; optionsBuilder .UseSqlServer( @"Server=(localdb)\msSqlLocalDB;Integrated Security=True; Database=EFCoreValueConvertion; MultipleActiveResultSets=true;" ); protected override void OnModelCreating(ModelBuilder modelBuilder) { foreach (var entity in modelBuilder.Model.GetEntityTypes()) { foreach (var property in entity.GetProperties()) { var attributes = property .PropertyInfo .GetCustomAttributes(typeof(SensitiveDataAttribute), false); if (attributes.Length &gt; 0) { property.SetValueConverter(new DataProtectionConverter()); } } } } } // DataProtectionConverter public class DataProtectionConverter : ValueConverter&lt;string, string&gt; { private static byte[] _chave = Encoding.UTF8.GetBytes("#lgpd+ef"); public DataProtectionConverter() : base(_convertTo, _convertFrom, default) { } private static Expression&lt;Func&lt;string, string&gt;&gt; _convertTo = x =&gt; LockView(x); private static Expression&lt;Func&lt;string, string&gt;&gt; _convertFrom = x =&gt; UnLockView(x); static string LockView(string texto) { using var hashProvider = new MD5CryptoServiceProvider(); var encriptar = new TripleDESCryptoServiceProvider { Mode = CipherMode.ECB, Key = hashProvider.ComputeHash(_chave), Padding = PaddingMode.PKCS7 }; using var transforme = encriptar.CreateEncryptor(); var dados = Encoding.UTF8.GetBytes(texto); return Convert.ToBase64String(transforme.TransformFinalBlock(dados, 0, dados.Length)); } static string UnLockView(string texto) { using var hashProvider = new MD5CryptoServiceProvider(); var descriptografar = new TripleDESCryptoServiceProvider { Mode = CipherMode.ECB, Key = hashProvider.ComputeHash(_chave), Padding = PaddingMode.PKCS7 }; using var transforme = descriptografar.CreateDecryptor(); var dados = Convert.FromBase64String(texto.Replace(" ", "+")); return Encoding.UTF8.GetString(transforme.TransformFinalBlock(dados, 0, dados.Length)); } } Output SQL Os comandos produzidos ficaram assim: Comando Inserir exec sp_executesql N'SET NOCOUNT ON; INSERT INTO [Clientes] ([CPF], [Endereco], [Nome], [Telefone]) VALUES (@p0, @p1, @p2, @p3); SELECT [Id] FROM [Clientes] WHERE @@ROWCOUNT = 1 AND [Id] = scope_identity(); ',N'@p0 nvarchar(4000),@p1 nvarchar(4000),@p2 nvarchar(4000),@p3 nvarchar(4000)', @p0=N'kOI/e7VQZhs=', -- Criptografado @p1=N'Aqui mesmo',@p2=N'Rafael Almeida', @p3=N'T2wQKyR8w28fKOgBXp0ytg==' -- Criptografado Comando Consultar SELECT TOP(1) [c].[Id], [c].[CPF], [c].[Endereco], [c].[Nome], [c].[Telefone] FROM [Clientes] AS [c] WHERE [c].[CPF] = N'kOI/e7VQZhs=' Observações Alguns banco de dados já fornecem criptografia de ponta-a-ponta, um banco de dados é apenas uma das ferramentas que podemos usar para que possamos estar em conformidade com LGPD/GDPR, uma dica é fique de olho na profissão de DPO (Data Protection Officer), será uma profissão que terá muitas vagas para os próximos anos, muitas empresas vão precisar desse profissional. Twitter Fico por aqui! 😄 Me siga no twitter: @ralmsdeveloper]]></summary></entry><entry><title type="html">Será que o Regex é rápido?</title><link href="http://old-blog.ralms.io/performance/entity%20framework%20core/regex/performanceregexvsspan01/" rel="alternate" type="text/html" title="Será que o Regex é rápido?" /><published>2023-06-13T00:00:00-03:00</published><updated>2023-06-13T00:00:00-03:00</updated><id>http://old-blog.ralms.io/performance/entity%20framework%20core/regex/performanceregexvsspan01</id><content type="html" xml:base="http://old-blog.ralms.io/performance/entity%20framework%20core/regex/performanceregexvsspan01/"><![CDATA[<p><img src="http://old-blog.ralms.io/assets/images/PerformanceRegex.png" alt="01" /></p>

<center><strong>Fala pessoal, tudo bem?!</strong></center>
<hr />

<p>Curiosidade leva nos sempre a pensar fora da caixa!!!<br /></p>
<div style="text-align: justify;">
No artigo <a href="https://ralms.io/dica/snakecase/" target="_BLANK" alt="">SNAKE CASE</a> eu usei um <b>REGEX</b> para aplicar 
a nomenclatura snake-case em uma <b>string</b>, mas hoje domingão (madrugada ainda rss), fiquei pensando de quanto performático era esse método.
</div>
<p><br /></p>
<h1 id="certo-e">Certo, e?</h1>
<div style="text-align: justify;">
Pois bem, fiquei inquieto e comecei a escrever alguns bits na tentativa de descobrir o que seria melhor em um 
ambiente onde eu precisaria processar milhares ou milhões de dados, então cheguei a construir alguns <b>métodos</b>, para garantir a performance em um ambiente crítico, onde pode acontecer milhares ou milhões de interações por segundos.<br />
<br />
Eu sou fã do projeto <b>Newtonsoft</b> por muito tempo ele entregou com maestria o que prometia, então fui estudar um pouco os fontes dele e me deparei com isso 
<a href="https://github.com/JamesNK/Newtonsoft.Json/blob/master/Src/Newtonsoft.Json/Utilities/StringUtils.cs#L218" target="_BLANK" alt="">AQUI</a>, então percebi que ele teve uma estratégia para aumentar a performance na serialização, eu poderia
 copiar esse método dele e fazer os testes que eu queria, mas, a minha experiência não seria a mesma, isso me motivou a criar alguns métodos que 
estão aqui neste pequeno artigo.
</div>
<p><br />
Vamos começar?!<br />
Veja os métodos que foram utilizados nos testes que executei.</p>
<h1 id="método-usando-regex">Método usando Regex</h1>
<p>Esse foi o método usado no artigo citado acima. Simples e objetivo usando todo poder do Regex!</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="kt">string</span> <span class="nf">ToSnakeCaseUsingRegex</span><span class="p">()</span>
<span class="p">{</span>
    <span class="k">return</span> <span class="n">Regex</span>
        <span class="p">.</span><span class="nf">Replace</span><span class="p">(</span>
            <span class="n">_frase</span><span class="p">,</span> 
            <span class="s">@"([a-z0-9])([A-Z])"</span><span class="p">,</span> 
            <span class="s">"$1_$2"</span><span class="p">,</span> 
            <span class="n">RegexOptions</span><span class="p">.</span><span class="n">Compiled</span><span class="p">)</span>
        <span class="p">.</span><span class="nf">ToLower</span><span class="p">();</span>
<span class="p">}</span>
</code></pre></div></div>
<h1 id="método-usando-linq">Método usando LINQ</h1>
<div style="text-align: justify;">
Não poderia passar por aqui sem falar da importancia do LINQ dentro do ecosistema .NET, sem sombra de dúvidas é uma das melhores implementações dentro da plataforma. 
O <b>LINQ</b> é simplesmente fantástico, pode ser usado praticamente pra manipular qualquer informação, eu te amo <b>LINQ</b>.
</div>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="kt">string</span> <span class="nf">ToSnakeCaseUsingLinq</span><span class="p">()</span>
<span class="p">{</span>
    <span class="k">return</span> <span class="kt">string</span>
        <span class="p">.</span><span class="nf">Concat</span><span class="p">(</span><span class="n">_frase</span>
            <span class="p">.</span><span class="nf">Select</span><span class="p">((</span><span class="n">c</span><span class="p">,</span> <span class="n">i</span><span class="p">)</span> <span class="p">=&gt;</span>
                <span class="n">i</span> <span class="p">&gt;</span> <span class="m">0</span> <span class="p">&amp;&amp;</span> <span class="kt">char</span><span class="p">.</span><span class="nf">IsUpper</span><span class="p">(</span><span class="n">c</span><span class="p">)</span> 
                    <span class="p">?</span> <span class="s">"_"</span> <span class="p">+</span> <span class="n">c</span> 
                    <span class="p">:</span> <span class="n">c</span><span class="p">.</span><span class="nf">ToString</span><span class="p">()))</span>
                <span class="p">.</span><span class="nf">ToLower</span><span class="p">();</span>
<span class="p">}</span>
</code></pre></div></div>
<h1 id="método-usando-stringbuilder-e-span">Método usando StringBuilder e Span<T></T></h1>
<div style="text-align: justify;">
Aqui vamos começar a brincadeira com essa nova implementação do .NET, o <b>SPAN</b>, quando se fala em gerenciamento 
de memória, lembre-se desse cara, nesse exemplo iremos fazer uma pequena mesclagem, com <b>SPAN</b> e o <b>StringBuilder</b> para empilhar temporariamente nossos caracteres.
</div>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="kt">string</span> <span class="nf">ToSnakeCaseUsingStringBuildAndSpan</span><span class="p">()</span>
<span class="p">{</span>
    <span class="n">ReadOnlySpan</span><span class="p">&lt;</span><span class="kt">char</span><span class="p">&gt;</span> <span class="n">frase</span> <span class="p">=</span> <span class="n">_frase</span><span class="p">;</span>

    <span class="kt">var</span> <span class="n">stringBuilder</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">StringBuilder</span><span class="p">();</span>

    <span class="k">for</span> <span class="p">(</span><span class="kt">var</span> <span class="n">i</span> <span class="p">=</span> <span class="m">0</span><span class="p">;</span> <span class="n">i</span> <span class="p">&lt;</span> <span class="n">frase</span><span class="p">.</span><span class="n">Length</span><span class="p">;</span> <span class="n">i</span><span class="p">++)</span>
    <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="kt">char</span><span class="p">.</span><span class="nf">IsUpper</span><span class="p">(</span><span class="n">frase</span><span class="p">[</span><span class="n">i</span><span class="p">])</span> <span class="p">&amp;&amp;</span> <span class="n">frase</span><span class="p">[</span><span class="m">0</span><span class="p">]</span> <span class="p">!=</span> <span class="n">frase</span><span class="p">[</span><span class="n">i</span><span class="p">])</span>
        <span class="p">{</span>
            <span class="n">stringBuilder</span><span class="p">.</span><span class="nf">Append</span><span class="p">(</span><span class="sc">'_'</span><span class="p">);</span>
            <span class="n">stringBuilder</span><span class="p">.</span><span class="nf">Append</span><span class="p">(</span><span class="n">frase</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
        <span class="p">}</span>
        <span class="k">else</span>
        <span class="p">{</span>
            <span class="n">stringBuilder</span><span class="p">.</span><span class="nf">Append</span><span class="p">(</span><span class="n">frase</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="k">return</span> <span class="n">stringBuilder</span>
        <span class="p">.</span><span class="nf">ToString</span><span class="p">()</span>
        <span class="p">.</span><span class="nf">ToLower</span><span class="p">();</span>
<span class="p">}</span>
</code></pre></div></div>
<h1 id="método-usando-somente-span">Método usando somente Span<T></T></h1>
<div style="text-align: justify;">
Aqui vamos usar o <b>SPAN</b>, só que a única diferença é que mudei a estratégia e estou usando um buffer para mover a posição dos caracteres.
</div>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="k">public</span> <span class="kt">string</span> <span class="nf">ToSnakeCaseUsingSpanOnBuffer</span><span class="p">()</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">undescores</span> <span class="p">=</span> <span class="m">0</span><span class="p">;</span>

    <span class="k">for</span> <span class="p">(</span><span class="kt">var</span> <span class="n">i</span> <span class="p">=</span> <span class="m">0</span><span class="p">;</span> <span class="n">i</span> <span class="p">&lt;</span> <span class="n">_frase</span><span class="p">.</span><span class="n">Length</span><span class="p">;</span> <span class="n">i</span><span class="p">++)</span>
    <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="kt">char</span><span class="p">.</span><span class="nf">IsUpper</span><span class="p">(</span><span class="n">_frase</span><span class="p">[</span><span class="n">i</span><span class="p">]))</span>
        <span class="p">{</span>
            <span class="n">undescores</span><span class="p">++;</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="kt">var</span> <span class="n">length</span> <span class="p">=</span> <span class="p">(</span><span class="n">undescores</span> <span class="p">+</span> <span class="n">_frase</span><span class="p">.</span><span class="n">Length</span><span class="p">)</span> <span class="p">-</span> <span class="m">1</span><span class="p">;</span>
    <span class="n">Span</span><span class="p">&lt;</span><span class="kt">char</span><span class="p">&gt;</span> <span class="n">buffer</span> <span class="p">=</span> <span class="k">new</span> <span class="kt">char</span><span class="p">[</span><span class="n">length</span><span class="p">];</span>
    <span class="kt">var</span> <span class="n">possitionOfBuffer</span> <span class="p">=</span> <span class="m">0</span><span class="p">;</span>
    <span class="kt">var</span> <span class="n">letterPosition</span> <span class="p">=</span> <span class="m">0</span><span class="p">;</span>

    <span class="k">while</span> <span class="p">(</span><span class="n">possitionOfBuffer</span> <span class="p">&lt;</span> <span class="n">buffer</span><span class="p">.</span><span class="n">Length</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">letterPosition</span> <span class="p">&gt;</span> <span class="m">0</span> <span class="p">&amp;&amp;</span> <span class="kt">char</span><span class="p">.</span><span class="nf">IsUpper</span><span class="p">(</span><span class="n">_frase</span><span class="p">[</span><span class="n">letterPosition</span><span class="p">]))</span>
        <span class="p">{</span>
            <span class="n">buffer</span><span class="p">[</span><span class="n">possitionOfBuffer</span><span class="p">]</span> <span class="p">=</span> <span class="sc">'_'</span><span class="p">;</span>
            <span class="n">buffer</span><span class="p">[</span><span class="n">possitionOfBuffer</span> <span class="p">+</span> <span class="m">1</span><span class="p">]</span> <span class="p">=</span> <span class="n">_frase</span><span class="p">[</span><span class="n">letterPosition</span><span class="p">];</span>
            <span class="n">possitionOfBuffer</span> <span class="p">+=</span> <span class="m">2</span><span class="p">;</span>
            <span class="n">letterPosition</span><span class="p">++;</span>
            <span class="k">continue</span><span class="p">;</span>
        <span class="p">}</span>

        <span class="n">buffer</span><span class="p">[</span><span class="n">possitionOfBuffer</span><span class="p">]</span> <span class="p">=</span> <span class="n">_frase</span><span class="p">[</span><span class="n">letterPosition</span><span class="p">];</span>

        <span class="n">possitionOfBuffer</span><span class="p">++;</span>
        <span class="n">letterPosition</span><span class="p">++;</span>
    <span class="p">}</span>

    <span class="k">return</span> <span class="n">buffer</span>
        <span class="p">.</span><span class="nf">ToString</span><span class="p">()</span>
        <span class="p">.</span><span class="nf">ToLower</span><span class="p">();</span>
<span class="p">}</span>
</code></pre></div></div>
<h1 id="resultado-dos-testes">Resultado dos testes</h1>
<p>Os testes foram realizando com 10, 100.000 e 1.000.000 de interações.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>-----------------------------------------------------------------
UsingStringBuilderAndSpan 10              Tempo: 00:00:00.0025257
                          100_000         Tempo: 00:00:00.1162287
                          1_000_000       Tempo: 00:00:02.0734867
-----------------------------------------------------------------
UsingSpanOnBuffer         10              Tempo: 00:00:00.0004815
                          100_000         Tempo: 00:00:00.1087459
                          1_000_000       Tempo: 00:00:01.0008935
-----------------------------------------------------------------
UsingRegex                10              Tempo: 00:00:00.0606576
                          100_000         Tempo: 00:00:00.5761851
                          1_000_000       Tempo: 00:00:06.2264039
-----------------------------------------------------------------
UsingLinq                 10              Tempo: 00:00:00.0089215
                          100_000         Tempo: 00:00:00.2520451
                          1_000_000       Tempo: 00:00:02.7254307
-----------------------------------------------------------------
</code></pre></div></div>
<div style="text-align: justify;">
Podemos observar que o <b>REGEX</b> teve a pior performance aqui, na verdade quando o assunto foi processar muita informação, ele foi péssimo, nossa 
mais de 6 segundos, em um ambiente de produção e crítico escorre até lágrimas dos olhos, já o <b>LINQ</b> me surpreendeu novamente 
mostrando que ainda é muito eficiente em cenários críticos, os métodos implementados usando <b>SPAN</b> tiveram a melhor performance.
 </div>
<p><br /></p>
<h1 id="benchmark">Benchmark</h1>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>BenchmarkDotNet=v0.12.0, OS=Windows 10.0.18362
Intel Core i7-7500U CPU 2.70GHz (Kaby Lake), 1 CPU, 4 logical and 2 physical cores
.NET Core SDK=3.1.100
  [Host]     : .NET Core 3.1.0 (CoreCLR 4.700.19.56402, CoreFX 4.700.19.56404), X64 RyuJIT  [AttachedDebugger]
  DefaultJob : .NET Core 3.1.0 (CoreCLR 4.700.19.56402, CoreFX 4.700.19.56404), X64 RyuJIT


|                             Method |       Mean |     Error |    StdDev |     Median | Rank |  Gen 0 | Gen 1 | Gen 2 | Allocated |
|----------------------------------- |-----------:|----------:|----------:|-----------:|-----:|-------:|------:|------:|----------:|
|       ToSnakeCaseUsingSpanOnBuffer |   387.2 ns |   6.99 ns |   6.54 ns |   387.0 ns |    1 | 0.1831 |     - |     - |     384 B |
| ToSnakeCaseUsingStringBuildAndSpan |   473.0 ns |   9.42 ns |  16.00 ns |   469.5 ns |    2 | 0.3328 |     - |     - |     696 B |
|               ToSnakeCaseUsingLinq | 1,763.3 ns |  69.64 ns | 198.68 ns | 1,680.1 ns |    3 | 0.7839 |     - |     - |    1640 B |
|              ToSnakeCaseUsingRegex | 5,438.9 ns | 193.14 ns | 531.95 ns | 5,292.9 ns |    4 | 1.1520 |     - |     - |    2416 B |
</code></pre></div></div>
<div style="text-align: justify;">
Podemos observar que o <b>REGEX</b> novamente teve a pior performance aqui, chegando a alocar mais de 2K na memória, enquanto o <b>LINQ</b> alocou apenas sua metade, 
e os métodos que usamos <b>SPAN</b> teve o melhor comportamento, alocando muito menos memória.
</div>
<p><br /></p>
<h1 id="um-pouco-sobre-span">Um pouco sobre Span<T></T></h1>
<div style="text-align: justify;">
O <b>Span</b> é uma struct, uma nova feature do .NET, o objetivo principal do team do .NET ter escrito é, diminuir o impacto na memória gerenciada, a heap, e, para 
eu não ser muito redundante tem um artigo muito legal do <b>Stephen Toub</b> 
falando mais sobre o Span, é basicamente o Deep-Dive dentro do Span.<br /> 
Fica dica de leitura: <a href="https://docs.microsoft.com/pt-br/archive/msdn-magazine/2018/january/csharp-all-about-span-exploring-a-new-net-mainstay" target="_BLANK" alt="">SPAN by Stephen Toub</a>.
</div>
<p><br /></p>

<h1 id="o-que-aprendemos-com-isso">O que aprendemos com isso?</h1>
<div class="notice--warning" style="text-align: justify;">
Aprendemos que mesmo que o .NET já nos forneça uma pilha de bibliotecas, com métodos quase prontos, não se acomode, em vez disso teste 
e analise seu cenário, quanto mais crítico ele for, mais a necessidade de performance você terá, pense fora da caixa, muitas das vezes você escrever seus próprios métodos pode ser a melhor opção.
</div>
<p><br /></p>

<p><br /></p>
<div class="notice--success">
<strong>
 Fico por aqui e um forte abraço! 😄 
</strong>
</div>

<p>#mvpbuzz #mvpbr #mvp #developerssergipe #share #vscode #performance #efcore7 #netcore7 #span<br /><br /></p>]]></content><author><name>Rafael Almeida</name><email>ralms@ralms.net</email></author><category term="Performance" /><category term="Entity Framework Core" /><category term="Regex" /><summary type="html"><![CDATA[Fala pessoal, tudo bem?! Curiosidade leva nos sempre a pensar fora da caixa!!! No artigo SNAKE CASE eu usei um REGEX para aplicar a nomenclatura snake-case em uma string, mas hoje domingão (madrugada ainda rss), fiquei pensando de quanto performático era esse método. Certo, e? Pois bem, fiquei inquieto e comecei a escrever alguns bits na tentativa de descobrir o que seria melhor em um ambiente onde eu precisaria processar milhares ou milhões de dados, então cheguei a construir alguns métodos, para garantir a performance em um ambiente crítico, onde pode acontecer milhares ou milhões de interações por segundos. Eu sou fã do projeto Newtonsoft por muito tempo ele entregou com maestria o que prometia, então fui estudar um pouco os fontes dele e me deparei com isso AQUI, então percebi que ele teve uma estratégia para aumentar a performance na serialização, eu poderia copiar esse método dele e fazer os testes que eu queria, mas, a minha experiência não seria a mesma, isso me motivou a criar alguns métodos que estão aqui neste pequeno artigo. Vamos começar?! Veja os métodos que foram utilizados nos testes que executei. Método usando Regex Esse foi o método usado no artigo citado acima. Simples e objetivo usando todo poder do Regex! public string ToSnakeCaseUsingRegex() { return Regex .Replace( _frase, @"([a-z0-9])([A-Z])", "$1_$2", RegexOptions.Compiled) .ToLower(); } Método usando LINQ Não poderia passar por aqui sem falar da importancia do LINQ dentro do ecosistema .NET, sem sombra de dúvidas é uma das melhores implementações dentro da plataforma. O LINQ é simplesmente fantástico, pode ser usado praticamente pra manipular qualquer informação, eu te amo LINQ. public string ToSnakeCaseUsingLinq() { return string .Concat(_frase .Select((c, i) =&gt; i &gt; 0 &amp;&amp; char.IsUpper(c) ? "_" + c : c.ToString())) .ToLower(); } Método usando StringBuilder e Span Aqui vamos começar a brincadeira com essa nova implementação do .NET, o SPAN, quando se fala em gerenciamento de memória, lembre-se desse cara, nesse exemplo iremos fazer uma pequena mesclagem, com SPAN e o StringBuilder para empilhar temporariamente nossos caracteres. public string ToSnakeCaseUsingStringBuildAndSpan() { ReadOnlySpan&lt;char&gt; frase = _frase; var stringBuilder = new StringBuilder(); for (var i = 0; i &lt; frase.Length; i++) { if (char.IsUpper(frase[i]) &amp;&amp; frase[0] != frase[i]) { stringBuilder.Append('_'); stringBuilder.Append(frase[i]); } else { stringBuilder.Append(frase[i]); } } return stringBuilder .ToString() .ToLower(); } Método usando somente Span Aqui vamos usar o SPAN, só que a única diferença é que mudei a estratégia e estou usando um buffer para mover a posição dos caracteres. public string ToSnakeCaseUsingSpanOnBuffer() { var undescores = 0; for (var i = 0; i &lt; _frase.Length; i++) { if (char.IsUpper(_frase[i])) { undescores++; } } var length = (undescores + _frase.Length) - 1; Span&lt;char&gt; buffer = new char[length]; var possitionOfBuffer = 0; var letterPosition = 0; while (possitionOfBuffer &lt; buffer.Length) { if (letterPosition &gt; 0 &amp;&amp; char.IsUpper(_frase[letterPosition])) { buffer[possitionOfBuffer] = '_'; buffer[possitionOfBuffer + 1] = _frase[letterPosition]; possitionOfBuffer += 2; letterPosition++; continue; } buffer[possitionOfBuffer] = _frase[letterPosition]; possitionOfBuffer++; letterPosition++; } return buffer .ToString() .ToLower(); } Resultado dos testes Os testes foram realizando com 10, 100.000 e 1.000.000 de interações. ----------------------------------------------------------------- UsingStringBuilderAndSpan 10 Tempo: 00:00:00.0025257 100_000 Tempo: 00:00:00.1162287 1_000_000 Tempo: 00:00:02.0734867 ----------------------------------------------------------------- UsingSpanOnBuffer 10 Tempo: 00:00:00.0004815 100_000 Tempo: 00:00:00.1087459 1_000_000 Tempo: 00:00:01.0008935 ----------------------------------------------------------------- UsingRegex 10 Tempo: 00:00:00.0606576 100_000 Tempo: 00:00:00.5761851 1_000_000 Tempo: 00:00:06.2264039 ----------------------------------------------------------------- UsingLinq 10 Tempo: 00:00:00.0089215 100_000 Tempo: 00:00:00.2520451 1_000_000 Tempo: 00:00:02.7254307 ----------------------------------------------------------------- Podemos observar que o REGEX teve a pior performance aqui, na verdade quando o assunto foi processar muita informação, ele foi péssimo, nossa mais de 6 segundos, em um ambiente de produção e crítico escorre até lágrimas dos olhos, já o LINQ me surpreendeu novamente mostrando que ainda é muito eficiente em cenários críticos, os métodos implementados usando SPAN tiveram a melhor performance. Benchmark BenchmarkDotNet=v0.12.0, OS=Windows 10.0.18362 Intel Core i7-7500U CPU 2.70GHz (Kaby Lake), 1 CPU, 4 logical and 2 physical cores .NET Core SDK=3.1.100 [Host] : .NET Core 3.1.0 (CoreCLR 4.700.19.56402, CoreFX 4.700.19.56404), X64 RyuJIT [AttachedDebugger] DefaultJob : .NET Core 3.1.0 (CoreCLR 4.700.19.56402, CoreFX 4.700.19.56404), X64 RyuJIT | Method | Mean | Error | StdDev | Median | Rank | Gen 0 | Gen 1 | Gen 2 | Allocated | |----------------------------------- |-----------:|----------:|----------:|-----------:|-----:|-------:|------:|------:|----------:| | ToSnakeCaseUsingSpanOnBuffer | 387.2 ns | 6.99 ns | 6.54 ns | 387.0 ns | 1 | 0.1831 | - | - | 384 B | | ToSnakeCaseUsingStringBuildAndSpan | 473.0 ns | 9.42 ns | 16.00 ns | 469.5 ns | 2 | 0.3328 | - | - | 696 B | | ToSnakeCaseUsingLinq | 1,763.3 ns | 69.64 ns | 198.68 ns | 1,680.1 ns | 3 | 0.7839 | - | - | 1640 B | | ToSnakeCaseUsingRegex | 5,438.9 ns | 193.14 ns | 531.95 ns | 5,292.9 ns | 4 | 1.1520 | - | - | 2416 B | Podemos observar que o REGEX novamente teve a pior performance aqui, chegando a alocar mais de 2K na memória, enquanto o LINQ alocou apenas sua metade, e os métodos que usamos SPAN teve o melhor comportamento, alocando muito menos memória. Um pouco sobre Span O Span é uma struct, uma nova feature do .NET, o objetivo principal do team do .NET ter escrito é, diminuir o impacto na memória gerenciada, a heap, e, para eu não ser muito redundante tem um artigo muito legal do Stephen Toub falando mais sobre o Span, é basicamente o Deep-Dive dentro do Span. Fica dica de leitura: SPAN by Stephen Toub. O que aprendemos com isso? Aprendemos que mesmo que o .NET já nos forneça uma pilha de bibliotecas, com métodos quase prontos, não se acomode, em vez disso teste e analise seu cenário, quanto mais crítico ele for, mais a necessidade de performance você terá, pense fora da caixa, muitas das vezes você escrever seus próprios métodos pode ser a melhor opção. Fico por aqui e um forte abraço! 😄 #mvpbuzz #mvpbr #mvp #developerssergipe #share #vscode #performance #efcore7 #netcore7 #span]]></summary></entry><entry><title type="html">Introdução ao LINQ</title><link href="http://old-blog.ralms.io/dotnet/performance/linq/introducao-linq/" rel="alternate" type="text/html" title="Introdução ao LINQ" /><published>2023-05-03T00:00:00-03:00</published><updated>2023-05-03T00:00:00-03:00</updated><id>http://old-blog.ralms.io/dotnet/performance/linq/introducao-linq</id><content type="html" xml:base="http://old-blog.ralms.io/dotnet/performance/linq/introducao-linq/"><![CDATA[<p><img src="http://old-blog.ralms.io/assets/images/net.png" alt="01" /></p>
<hr />

<div class="notice--warning" style="background-color:#f8ffc4">
Uma pequena introdução ao LINQ
</div>

<h3 id="simplificando-consultas-e-manipulações-de-dados-com-linq-em-net">Simplificando Consultas e Manipulações de Dados com LINQ em .NET</h3>
<p>O Language Integrated Query (LINQ) é uma das características mais poderosas do .NET Framework e .NET Core e agora apenas .NET oferece uma maneira uniforme e intuitiva de realizar consultas e manipulações de dados em várias fontes de dados, como coleções, bancos de dados e serviços da web. Neste artigo, vamos explorar o LINQ em detalhes, destacando sua sintaxe, recursos avançados e fornecendo exemplos práticos para ajudar você a dominar essa ferramenta essencial no desenvolvimento .NET.</p>

<h3 id="o-que-é-linq">O que é LINQ?</h3>
<p>O LINQ é uma abreviação de Language Integrated Query, que permite escrever consultas diretamente em C# ou outras linguagens .NET, tornando o código mais legível, conciso e expressivo. Ele fornece uma sintaxe semelhante à SQL para consultas de dados, mas com a vantagem de ser fortemente tipado e integrado ao ambiente de desenvolvimento.</p>

<h3 id="sintaxe-básica-do-linq">Sintaxe Básica do LINQ</h3>
<p>A sintaxe básica do LINQ é simples e compreensível. Ela envolve três etapas principais: from, where e select.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">resultado</span> <span class="p">=</span> <span class="k">from</span> <span class="n">item</span> <span class="k">in</span> <span class="n">colecao</span>
                <span class="k">where</span> <span class="n">condi</span><span class="err">çã</span><span class="n">o</span>
                <span class="k">select</span> <span class="n">item</span><span class="p">;</span>

</code></pre></div></div>
<p>from: Define a fonte de dados e a variável de intervalo que representa cada elemento da coleção.</p>

<p>where: Aplica uma condição de filtro aos elementos da coleção.</p>

<p>select: Projeta os resultados da consulta, selecionando os itens desejados.</p>
<h2 id="funcionalidades-avançadas-do-linq">Funcionalidades Avançadas do LINQ</h2>
<h3 id="operações-de-projeção">Operações de Projeção</h3>
<p>O LINQ permite projetar os resultados da consulta em diferentes formatos, como listas, arrays ou tipos personalizados.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">nomes</span> <span class="p">=</span> <span class="k">from</span> <span class="n">pessoa</span> <span class="k">in</span> <span class="n">pessoas</span>
            <span class="k">select</span> <span class="n">pessoa</span><span class="p">.</span><span class="n">Nome</span><span class="p">;</span>
</code></pre></div></div>
<h3 id="ordenação">Ordenação</h3>
<p>É possível ordenar os resultados da consulta usando a palavra-chave orderby.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">numerosOrdenados</span> <span class="p">=</span> 
  <span class="k">from</span> <span class="n">numero</span> <span class="k">in</span> <span class="n">numeros</span>
    <span class="k">orderby</span> <span class="n">numero</span> <span class="k">descending</span>
    <span class="k">select</span> <span class="n">numero</span><span class="p">;</span>
</code></pre></div></div>

<h3 id="operações-de-agregação">Operações de Agregação</h3>
<p>O LINQ suporta várias operações de agregação, como Count, Sum, Average, Min e Max.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">soma</span> <span class="p">=</span> <span class="n">numeros</span><span class="p">.</span><span class="nf">Sum</span><span class="p">();</span>
<span class="kt">var</span> <span class="n">media</span> <span class="p">=</span> <span class="n">numeros</span><span class="p">.</span><span class="nf">Average</span><span class="p">();</span>
<span class="kt">var</span> <span class="n">quantidade</span> <span class="p">=</span> <span class="n">numeros</span><span class="p">.</span><span class="nf">Count</span><span class="p">();</span>

</code></pre></div></div>
<h3 id="consultas-aninhadas">Consultas Aninhadas</h3>
<p>Consultas LINQ podem ser aninhadas para realizar operações complexas e relacionadas.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">pessoasComMaisDeDezoitoAnos</span> <span class="p">=</span> <span class="k">from</span> <span class="n">pessoa</span> <span class="k">in</span> <span class="n">pessoas</span>
    <span class="k">where</span> <span class="n">pessoa</span><span class="p">.</span><span class="n">Idade</span> <span class="p">&gt;</span> <span class="m">18</span>
    <span class="k">select</span> <span class="k">new</span>
    <span class="p">{</span>
        <span class="n">pessoa</span><span class="p">.</span><span class="n">Nome</span><span class="p">,</span>
        <span class="n">Enderecos</span> <span class="p">=</span> <span class="k">from</span> <span class="n">endereco</span> <span class="k">in</span> <span class="n">pessoa</span><span class="p">.</span><span class="n">Enderecos</span>
                    <span class="k">where</span> <span class="n">endereco</span><span class="p">.</span><span class="n">Cidade</span> <span class="p">==</span> <span class="s">"Aracaju"</span>
                    <span class="k">select</span> <span class="n">endereco</span>
    <span class="p">};</span>
</code></pre></div></div>

<h3 id="considerações-finais">Considerações finais</h3>
<p>O LINQ é uma ferramenta poderosa e flexível que simplifica significativamente a manipulação e consulta de dados em aplicativos .NET. Com sua sintaxe intuitiva e recursos avançados, o LINQ permite que os desenvolvedores escrevam consultas complexas de forma eficiente e legível. Ao dominar o LINQ, você aumentará sua produtividade e escreverá código mais limpo e robusto em seus projetos .NET.</p>

<h2 id="contatos">Contatos</h2>
<div class="notice--info">
 Fico por aqui, mas pode me contatar por meio de minhas redes sociais 😄 <br />
 twitter: <a alt="" href="https://twitter.com/RalmsDeveloper">@ralmsdeveloper</a><br />
 linkedin: <a alt="" href="https://www.linkedin.com/in/ralmsdeveloper/">@ralmsdeveloper</a><br />
</div>]]></content><author><name>Rafael Almeida</name><email>ralms@ralms.net</email></author><category term="dotnet" /><category term="performance" /><category term="LINQ" /><summary type="html"><![CDATA[Uma pequena introdução ao LINQ Simplificando Consultas e Manipulações de Dados com LINQ em .NET O Language Integrated Query (LINQ) é uma das características mais poderosas do .NET Framework e .NET Core e agora apenas .NET oferece uma maneira uniforme e intuitiva de realizar consultas e manipulações de dados em várias fontes de dados, como coleções, bancos de dados e serviços da web. Neste artigo, vamos explorar o LINQ em detalhes, destacando sua sintaxe, recursos avançados e fornecendo exemplos práticos para ajudar você a dominar essa ferramenta essencial no desenvolvimento .NET. O que é LINQ? O LINQ é uma abreviação de Language Integrated Query, que permite escrever consultas diretamente em C# ou outras linguagens .NET, tornando o código mais legível, conciso e expressivo. Ele fornece uma sintaxe semelhante à SQL para consultas de dados, mas com a vantagem de ser fortemente tipado e integrado ao ambiente de desenvolvimento. Sintaxe Básica do LINQ A sintaxe básica do LINQ é simples e compreensível. Ela envolve três etapas principais: from, where e select. var resultado = from item in colecao where condição select item; from: Define a fonte de dados e a variável de intervalo que representa cada elemento da coleção. where: Aplica uma condição de filtro aos elementos da coleção. select: Projeta os resultados da consulta, selecionando os itens desejados. Funcionalidades Avançadas do LINQ Operações de Projeção O LINQ permite projetar os resultados da consulta em diferentes formatos, como listas, arrays ou tipos personalizados. var nomes = from pessoa in pessoas select pessoa.Nome; Ordenação É possível ordenar os resultados da consulta usando a palavra-chave orderby. var numerosOrdenados = from numero in numeros orderby numero descending select numero; Operações de Agregação O LINQ suporta várias operações de agregação, como Count, Sum, Average, Min e Max. var soma = numeros.Sum(); var media = numeros.Average(); var quantidade = numeros.Count(); Consultas Aninhadas Consultas LINQ podem ser aninhadas para realizar operações complexas e relacionadas. var pessoasComMaisDeDezoitoAnos = from pessoa in pessoas where pessoa.Idade &gt; 18 select new { pessoa.Nome, Enderecos = from endereco in pessoa.Enderecos where endereco.Cidade == "Aracaju" select endereco }; Considerações finais O LINQ é uma ferramenta poderosa e flexível que simplifica significativamente a manipulação e consulta de dados em aplicativos .NET. Com sua sintaxe intuitiva e recursos avançados, o LINQ permite que os desenvolvedores escrevam consultas complexas de forma eficiente e legível. Ao dominar o LINQ, você aumentará sua produtividade e escreverá código mais limpo e robusto em seus projetos .NET. Contatos Fico por aqui, mas pode me contatar por meio de minhas redes sociais 😄 twitter: @ralmsdeveloper linkedin: @ralmsdeveloper]]></summary></entry><entry><title type="html">Atualização em Massa</title><link href="http://old-blog.ralms.io/dotnet/performance/entity%20framework%20core/entity%20framework%20core%207/news-bacth/" rel="alternate" type="text/html" title="Atualização em Massa" /><published>2023-04-25T00:00:00-03:00</published><updated>2023-04-25T00:00:00-03:00</updated><id>http://old-blog.ralms.io/dotnet/performance/entity%20framework%20core/entity%20framework%20core%207/news-bacth</id><content type="html" xml:base="http://old-blog.ralms.io/dotnet/performance/entity%20framework%20core/entity%20framework%20core%207/news-bacth/"><![CDATA[<p><img src="http://old-blog.ralms.io/assets/images/dicasefcore.png" alt="01" /></p>
<hr />

<div class="notice--warning" style="background-color:#f8ffc4">
Nesse post apresento melhorias de mais novidades do EF Core 7
</div>

<h2 id="ef-core-7-atualização-e-exclusão-em-massa-com-eficiência">EF CORE 7 Atualização e Exclusão em Massa com Eficiência</h2>
<p>O EF Core 7 introduziu novos métodos, ExecuteDelete e ExecuteUpdate, para otimizar a atualização e exclusão de grandes volumes de dados no banco de dados. Estes métodos oferecem uma alternativa mais eficiente ao uso tradicional do SaveChanges para grandes conjuntos de dados.</p>

<h2 id="executedelete">ExecuteDelete</h2>

<p>O método ExecuteDelete remove um conjunto de entidades de acordo com um predicado especificado. Esse predicado define quais entidades devem ser excluídas, similarmente à cláusula WHERE em uma consulta SQL.</p>

<p>Exemplo de uso:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">context</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">RalmsContext</span><span class="p">())</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">ordersToDelete</span> <span class="p">=</span> <span class="n">context</span><span class="p">.</span><span class="n">Orders</span><span class="p">.</span><span class="nf">Where</span><span class="p">(</span><span class="n">o</span> <span class="p">=&gt;</span> <span class="n">o</span><span class="p">.</span><span class="n">OrderDate</span> <span class="p">&lt;</span> <span class="k">new</span> <span class="nf">DateTime</span><span class="p">(</span><span class="m">2023</span><span class="p">,</span> <span class="m">1</span><span class="p">,</span> <span class="m">1</span><span class="p">));</span>
    <span class="n">context</span><span class="p">.</span><span class="n">Database</span><span class="p">.</span><span class="nf">ExecuteDelete</span><span class="p">(</span><span class="n">ordersToDelete</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="executeupdate">ExecuteUpdate</h2>

<p>O método ExecuteUpdate atualiza as propriedades de um conjunto de entidades de acordo com os valores especificados. Similarmente ao ExecuteDelete, utiliza-se um predicado para definir quais entidades serão atualizadas.</p>

<p>Exemplo de uso:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">context</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">RalmsContext</span><span class="p">())</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">ordersToUpdate</span> <span class="p">=</span> <span class="n">context</span><span class="p">.</span><span class="n">Orders</span><span class="p">.</span><span class="nf">Where</span><span class="p">(</span><span class="n">o</span> <span class="p">=&gt;</span> <span class="n">o</span><span class="p">.</span><span class="n">OrderStatus</span> <span class="p">==</span> <span class="n">OrderStatus</span><span class="p">.</span><span class="n">Pending</span><span class="p">);</span>
    <span class="n">context</span><span class="p">.</span><span class="n">Database</span><span class="p">.</span><span class="nf">ExecuteUpdate</span><span class="p">(</span><span class="n">ordersToUpdate</span><span class="p">,</span> <span class="n">o</span> <span class="p">=&gt;</span> <span class="k">new</span> <span class="p">{</span> <span class="n">o</span><span class="p">.</span><span class="n">OrderStatus</span> <span class="p">=</span> <span class="n">OrderStatus</span><span class="p">.</span><span class="n">Shipped</span> <span class="p">});</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="vantagens">Vantagens</h2>

<p>Eficiência: ExecuteDelete e ExecuteUpdate executam comandos SQL únicos e otimizados, resultando em um desempenho significativamente melhor para grandes conjuntos de dados.
Flexibilidade: Os predicados permitem definir com precisão quais entidades devem ser atualizadas ou excluídas.
Transações: A utilização de transações é compatível com os métodos, garantindo a integridade dos dados em caso de falhas.</p>

<h2 id="considerações">Considerações</h2>

<p>Rastreamento de entidades que ao contrário do SaveChanges, os métodos não rastreiam o estado das entidades no contexto.</p>

<p>Consultas Subsequentas: As alterações realizadas com ExecuteDelete e ExecuteUpdate não são automaticamente refletidas no contexto, portanto, consultas subsequentes podem precisar ser recarregadas.</p>

<p>Segurança: O predicado deve ser cuidadosamente escrito para evitar exclusões ou atualizações indesejadas.</p>

<h2 id="contatos">Contatos</h2>
<div class="notice--info">
 Fico por aqui, mas pode me contatar por meio de minhas redes sociais 😄 <br />
 twitter: <a alt="" href="https://twitter.com/RalmsDeveloper">@ralmsdeveloper</a><br />
 linkedin: <a alt="" href="https://www.linkedin.com/in/ralmsdeveloper/">@ralmsdeveloper</a><br />
</div>]]></content><author><name>Rafael Almeida</name><email>ralms@ralms.net</email></author><category term="dotnet" /><category term="performance" /><category term="Entity Framework Core" /><category term="Entity Framework Core 7" /><summary type="html"><![CDATA[Nesse post apresento melhorias de mais novidades do EF Core 7 EF CORE 7 Atualização e Exclusão em Massa com Eficiência O EF Core 7 introduziu novos métodos, ExecuteDelete e ExecuteUpdate, para otimizar a atualização e exclusão de grandes volumes de dados no banco de dados. Estes métodos oferecem uma alternativa mais eficiente ao uso tradicional do SaveChanges para grandes conjuntos de dados. ExecuteDelete O método ExecuteDelete remove um conjunto de entidades de acordo com um predicado especificado. Esse predicado define quais entidades devem ser excluídas, similarmente à cláusula WHERE em uma consulta SQL. Exemplo de uso: using (var context = new RalmsContext()) { var ordersToDelete = context.Orders.Where(o =&gt; o.OrderDate &lt; new DateTime(2023, 1, 1)); context.Database.ExecuteDelete(ordersToDelete); } ExecuteUpdate O método ExecuteUpdate atualiza as propriedades de um conjunto de entidades de acordo com os valores especificados. Similarmente ao ExecuteDelete, utiliza-se um predicado para definir quais entidades serão atualizadas. Exemplo de uso: using (var context = new RalmsContext()) { var ordersToUpdate = context.Orders.Where(o =&gt; o.OrderStatus == OrderStatus.Pending); context.Database.ExecuteUpdate(ordersToUpdate, o =&gt; new { o.OrderStatus = OrderStatus.Shipped }); } Vantagens Eficiência: ExecuteDelete e ExecuteUpdate executam comandos SQL únicos e otimizados, resultando em um desempenho significativamente melhor para grandes conjuntos de dados. Flexibilidade: Os predicados permitem definir com precisão quais entidades devem ser atualizadas ou excluídas. Transações: A utilização de transações é compatível com os métodos, garantindo a integridade dos dados em caso de falhas. Considerações Rastreamento de entidades que ao contrário do SaveChanges, os métodos não rastreiam o estado das entidades no contexto. Consultas Subsequentas: As alterações realizadas com ExecuteDelete e ExecuteUpdate não são automaticamente refletidas no contexto, portanto, consultas subsequentes podem precisar ser recarregadas. Segurança: O predicado deve ser cuidadosamente escrito para evitar exclusões ou atualizações indesejadas. Contatos Fico por aqui, mas pode me contatar por meio de minhas redes sociais 😄 twitter: @ralmsdeveloper linkedin: @ralmsdeveloper]]></summary></entry><entry><title type="html">EF Core 7 chega a ser 44x mais rápido!</title><link href="http://old-blog.ralms.io/dotnet/performance/entity%20framework%20core/entity%20framework%20core%207/ef-core-7-performance-part-1/" rel="alternate" type="text/html" title="EF Core 7 chega a ser 44x mais rápido!" /><published>2023-04-02T00:00:00-03:00</published><updated>2023-04-02T00:00:00-03:00</updated><id>http://old-blog.ralms.io/dotnet/performance/entity%20framework%20core/entity%20framework%20core%207/ef-core-7-performance-part-1</id><content type="html" xml:base="http://old-blog.ralms.io/dotnet/performance/entity%20framework%20core/entity%20framework%20core%207/ef-core-7-performance-part-1/"><![CDATA[<p><img src="http://old-blog.ralms.io/assets/images/efcore7/topo.png" alt="01" /></p>
<hr />

<div class="notice--warning" style="background-color:#f8ffc4">
Este pequeno post é pra comemorar o lançamento do Entity Framework Core 7 e algumas observações pessoais, fiz alguns teses enquanto testava a performance
de Minimal API vs MVC, e obtive mais 500% de performance com as novas features, isso é simplesmente fantástico!
</div>

<h2 id="introdução">Introdução</h2>
<div style="text-align: justify;">
O Team do <b>EF Core</b> tem se dedicado bastante a melhorar o produto desde sua reescrita e lançamento oficial em 2016, todos ou quase todos sabem que o ORM foi <b>reescrito 100% do zero</b>, dado que a arquitetura anterior já impedia grandes evoluções no produto.
<br /><br />
A cada versão do produto geralmente costumamos ver diversas features sendo implementadas no produto, sendo que na versão <b>EF Core 6</b> e agora o<b> EF Core 7</b> não contém tantas features como costumávamos a ver, isso tem um motivo, o produto está ficando cada vez mais maduro e estável, além disso foco tem sido em melhorias de performance e features já existentes.
<br />
<br />
A versão do <b>EF Core 7</b> foi lançada oficialmente no 8 de novembro de 2022, ela não trouxe diversas novidades, mas trouxe algumas extremantes valiosas que são:
</div>
<ul>
  <li>Suporte JSON nativo</li>
  <li>Insert mais rápido</li>
  <li>Suporte atualização em massa</li>
  <li>Suporte exclusão em massa</li>
</ul>

<h2 id="atualização-em-massa">Atualização em massa</h2>
<div style="text-align: justify;">
Estarei focando aqui na atualização e exclusão em massa, dado que temos um ganho significativo de performance, vale lembrar que existem outras formas de atingir praticamente o mesmo objetivo que será apresentado, porém era workaround nada nativo do ORM.
<br /><br />
A atualização e exclusão em massa foi um dos tópicos mais comentados e solicitados no github do projeto, inclusive o próprio team do EF Core fez uma apresentação onde disponibilizou um gráfico de performance e os ganhos que tivemos desde o EF 6, chegando a ser 44x mais rápido com as novas features implementadas.
</div>
<p><img src="http://old-blog.ralms.io/assets/images/efcore7/image01.png" alt="01" />
 <br /> <br />
 <img src="http://old-blog.ralms.io/assets/images/efcore7/image02.png" alt="01" /></p>

<p>Fonte imagens: <a href="https://view.officeapps.live.com/op/view.aspx?src=https%3A%2F%2Fraw.githubusercontent.com%2Fajcvickers%2FBlogManagementApi%2Fmain%2FLevelingUpData_v2.pptx&amp;wdOrigin=BROWSELINK" alt="">PPT do Team EF Core</a></p>

<h2 id="entendendo-o-problema">Entendendo o problema</h2>
<div style="text-align: justify;">
Quando a gente precisava excluir ou atualizar uma massa de registros e existia a necessidade de aplicar um filtro para que as modificações fosse restrita apenas a um conjunto de dados, tínhamos que executar uma instrução bruta fora do capô do ORM ou consultar os dados via ORM para que os objetos fossem traqueados, executar a lógica desejada exclusão ou atualização do objeto e depois chamar o método <b>SaveChanges</b>, vamos pegar exemplo hipotético aqui de atualização de desconto para todos clientes do estado de São Paulo, a gente usava algo assim:
</div>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">customers</span> <span class="p">=</span> <span class="n">db</span><span class="p">.</span><span class="n">Customers</span><span class="p">.</span><span class="nf">Where</span><span class="p">(</span><span class="n">p</span> <span class="p">=&gt;</span> <span class="n">p</span><span class="p">.</span><span class="n">State</span> <span class="p">==</span> <span class="s">"SP"</span><span class="p">);</span>
<span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">customer</span> <span class="k">in</span> <span class="n">customers</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">customer</span><span class="p">.</span><span class="n">Discount</span> <span class="p">=</span> <span class="m">10</span><span class="n">m</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">db</span><span class="p">.</span><span class="nf">SaveChanges</span><span class="p">();</span>
</code></pre></div></div>
<p>Isso era o que a gente tinha para o momento, mas o custo de CPU e memória era muito alto, a instrução para atualização em massa era muito ruim dado que era gerado um comando para cada objeto afetado pela aplicação, veja um exemplo:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="p">[</span><span class="n">Parameters</span><span class="p">=[</span><span class="n">@p1</span><span class="p">=</span><span class="err">'</span><span class="m">967</span><span class="err">'</span><span class="p">,</span> <span class="n">@p0</span><span class="p">=</span><span class="err">'</span><span class="m">10</span><span class="err">'</span> <span class="p">(</span><span class="n">Precision</span> <span class="p">=</span> <span class="m">18</span><span class="p">)</span> <span class="p">(</span><span class="n">Scale</span> <span class="p">=</span> <span class="m">2</span><span class="p">),</span> <span class="n">@p3</span><span class="p">=</span><span class="err">'</span><span class="m">968</span><span class="err">'</span><span class="p">,</span> <span class="n">@p2</span><span class="p">=</span><span class="err">'</span><span class="m">10</span><span class="err">'</span> <span class="p">(</span><span class="n">Precision</span> <span class="p">=</span> <span class="m">18</span><span class="p">)</span> <span class="p">(</span><span class="n">Scale</span> <span class="p">=</span> <span class="m">2</span><span class="p">),</span> <span class="n">@p5</span><span class="p">=</span><span class="err">'</span><span class="m">969</span><span class="err">'</span><span class="p">,</span> <span class="n">@p4</span><span class="p">=</span><span class="err">'</span><span class="m">10</span><span class="err">'</span> <span class="p">(</span><span class="n">Precision</span> <span class="p">=</span> <span class="m">18</span><span class="p">)</span> <span class="p">(</span><span class="n">Scale</span> <span class="p">=</span> <span class="m">2</span><span class="p">),</span> <span class="n">@p7</span><span class="p">=</span><span class="err">'</span><span class="m">970</span><span class="err">'</span><span class="p">,</span> <span class="n">@p6</span><span class="p">=</span><span class="err">'</span><span class="m">10</span><span class="err">'</span> <span class="p">(</span><span class="n">Precision</span> <span class="p">=</span> <span class="m">18</span><span class="p">)</span> <span class="p">(</span><span class="n">Scale</span> <span class="p">=</span> <span class="m">2</span><span class="p">),</span> <span class="n">@p9</span><span class="p">=</span><span class="err">'</span><span class="m">971</span><span class="err">'</span><span class="p">,</span> <span class="n">@p8</span><span class="p">=</span><span class="err">'</span><span class="m">10</span><span class="err">'</span> <span class="p">(</span><span class="n">Precision</span> <span class="p">=</span> <span class="m">18</span><span class="p">)</span> <span class="p">(</span><span class="n">Scale</span> <span class="p">=</span> <span class="m">2</span><span class="p">),</span> <span class="n">@p11</span><span class="p">=</span><span class="err">'</span><span class="m">972</span><span class="err">'</span><span class="p">,</span> <span class="n">@p10</span><span class="p">=</span><span class="err">'</span><span class="m">10</span><span class="err">'</span> <span class="p">(</span><span class="n">Precision</span> <span class="p">=</span> <span class="m">18</span><span class="p">)</span> <span class="p">(</span><span class="n">Scale</span> <span class="p">=</span> <span class="m">2</span><span class="p">),</span> <span class="n">@p13</span><span class="p">=</span><span class="err">'</span><span class="m">973</span><span class="err">'</span><span class="p">,</span> <span class="n">@p12</span><span class="p">=</span><span class="err">'</span><span class="m">10</span><span class="err">'</span> <span class="p">(</span><span class="n">Precision</span> <span class="p">=</span> <span class="m">18</span><span class="p">)</span> <span class="p">(</span><span class="n">Scale</span> <span class="p">=</span> <span class="m">2</span><span class="p">),</span> <span class="n">@p15</span><span class="p">=</span><span class="err">'</span><span class="m">974</span><span class="err">'</span><span class="p">,</span> <span class="n">@p14</span><span class="p">=</span><span class="err">'</span><span class="m">10</span><span class="err">'</span> <span class="p">(</span><span class="n">Precision</span> <span class="p">=</span> <span class="m">18</span><span class="p">)</span> <span class="p">(</span><span class="n">Scale</span> <span class="p">=</span> <span class="m">2</span><span class="p">),</span> <span class="n">@p17</span><span class="p">=</span><span class="err">'</span><span class="m">975</span><span class="err">'</span><span class="p">,</span> <span class="n">@p16</span><span class="p">=</span><span class="err">'</span><span class="m">10</span><span class="err">'</span> <span class="p">(</span><span class="n">Precision</span> <span class="p">=</span> <span class="m">18</span><span class="p">)</span> <span class="p">(</span><span class="n">Scale</span> <span class="p">=</span> <span class="m">2</span><span class="p">),</span> <span class="n">@p19</span><span class="p">=</span><span class="err">'</span><span class="m">976</span><span class="err">'</span><span class="p">,</span> <span class="n">@p18</span><span class="p">=</span><span class="err">'</span><span class="m">10</span><span class="err">'</span> <span class="p">(</span><span class="n">Precision</span> <span class="p">=</span> <span class="m">18</span><span class="p">)</span> <span class="p">(</span><span class="n">Scale</span> <span class="p">=</span> <span class="m">2</span><span class="p">),</span> <span class="n">@p21</span><span class="p">=</span><span class="err">'</span><span class="m">977</span><span class="err">'</span><span class="p">,</span> <span class="n">@p20</span><span class="p">=</span><span class="err">'</span><span class="m">10</span><span class="err">'</span> <span class="p">(</span><span class="n">Precision</span> <span class="p">=</span> <span class="m">18</span><span class="p">)</span> <span class="p">(</span><span class="n">Scale</span> <span class="p">=</span> <span class="m">2</span><span class="p">),</span> <span class="n">@p23</span><span class="p">=</span><span class="err">'</span><span class="m">978</span><span class="err">'</span><span class="p">,</span> <span class="n">@p22</span><span class="p">=</span><span class="err">'</span><span class="m">10</span><span class="err">'</span> <span class="p">(</span><span class="n">Precision</span> <span class="p">=</span> <span class="m">18</span><span class="p">)</span> <span class="p">(</span><span class="n">Scale</span> <span class="p">=</span> <span class="m">2</span><span class="p">),</span> <span class="n">@p25</span><span class="p">=</span><span class="err">'</span><span class="m">979</span><span class="err">'</span><span class="p">,</span> <span class="n">@p24</span><span class="p">=</span><span class="err">'</span><span class="m">10</span><span class="err">'</span> <span class="p">(</span><span class="n">Precision</span> <span class="p">=</span> <span class="m">18</span><span class="p">)</span> <span class="p">(</span><span class="n">Scale</span> <span class="p">=</span> <span class="m">2</span><span class="p">),</span> <span class="n">@p27</span><span class="p">=</span><span class="err">'</span><span class="m">980</span><span class="err">'</span><span class="p">,</span> <span class="n">@p26</span><span class="p">=</span><span class="err">'</span><span class="m">10</span><span class="err">'</span> <span class="p">(</span><span class="n">Precision</span> <span class="p">=</span> <span class="m">18</span><span class="p">)</span> <span class="p">(</span><span class="n">Scale</span> <span class="p">=</span> <span class="m">2</span><span class="p">),</span> <span class="n">@p29</span><span class="p">=</span><span class="err">'</span><span class="m">981</span><span class="err">'</span><span class="p">,</span> <span class="n">@p28</span><span class="p">=</span><span class="err">'</span><span class="m">10</span><span class="err">'</span> <span class="p">(</span><span class="n">Precision</span> <span class="p">=</span> <span class="m">18</span><span class="p">)</span> <span class="p">(</span><span class="n">Scale</span> <span class="p">=</span> <span class="m">2</span><span class="p">),</span> <span class="n">@p31</span><span class="p">=</span><span class="err">'</span><span class="m">982</span><span class="err">'</span><span class="p">,</span> <span class="n">@p30</span><span class="p">=</span><span class="err">'</span><span class="m">10</span><span class="err">'</span> <span class="p">(</span><span class="n">Precision</span> <span class="p">=</span> <span class="m">18</span><span class="p">)</span> <span class="p">(</span><span class="n">Scale</span> <span class="p">=</span> <span class="m">2</span><span class="p">),</span> <span class="n">@p33</span><span class="p">=</span><span class="err">'</span><span class="m">983</span><span class="err">'</span><span class="p">,</span> <span class="n">@p32</span><span class="p">=</span><span class="err">'</span><span class="m">10</span><span class="err">'</span> <span class="p">(</span><span class="n">Precision</span> <span class="p">=</span> <span class="m">18</span><span class="p">)</span> <span class="p">(</span><span class="n">Scale</span> <span class="p">=</span> <span class="m">2</span><span class="p">),</span> <span class="n">@p35</span><span class="p">=</span><span class="err">'</span><span class="m">984</span><span class="err">'</span><span class="p">,</span> <span class="n">@p34</span><span class="p">=</span><span class="err">'</span><span class="m">10</span><span class="err">'</span> <span class="p">(</span><span class="n">Precision</span> <span class="p">=</span> <span class="m">18</span><span class="p">)</span> <span class="p">(</span><span class="n">Scale</span> <span class="p">=</span> <span class="m">2</span><span class="p">),</span> <span class="n">@p37</span><span class="p">=</span><span class="err">'</span><span class="m">985</span><span class="err">'</span><span class="p">,</span> <span class="n">@p36</span><span class="p">=</span><span class="err">'</span><span class="m">10</span><span class="err">'</span> <span class="p">(</span><span class="n">Precision</span> <span class="p">=</span> <span class="m">18</span><span class="p">)</span> <span class="p">(</span><span class="n">Scale</span> <span class="p">=</span> <span class="m">2</span><span class="p">),</span> <span class="n">@p39</span><span class="p">=</span><span class="err">'</span><span class="m">986</span><span class="err">'</span><span class="p">,</span> <span class="n">@p38</span><span class="p">=</span><span class="err">'</span><span class="m">10</span><span class="err">'</span> <span class="p">(</span><span class="n">Precision</span> <span class="p">=</span> <span class="m">18</span><span class="p">)</span> <span class="p">(</span><span class="n">Scale</span> <span class="p">=</span> <span class="m">2</span><span class="p">),</span> <span class="n">@p41</span><span class="p">=</span><span class="err">'</span><span class="m">987</span><span class="err">'</span><span class="p">,</span> <span class="n">@p40</span><span class="p">=</span><span class="err">'</span><span class="m">10</span><span class="err">'</span> <span class="p">(</span><span class="n">Precision</span> <span class="p">=</span> <span class="m">18</span><span class="p">)</span> <span class="p">(</span><span class="n">Scale</span> <span class="p">=</span> <span class="m">2</span><span class="p">),</span> <span class="n">@p43</span><span class="p">=</span><span class="err">'</span><span class="m">988</span><span class="err">'</span><span class="p">,</span> <span class="n">@p42</span><span class="p">=</span><span class="err">'</span><span class="m">10</span><span class="err">'</span> <span class="p">(</span><span class="n">Precision</span> <span class="p">=</span> <span class="m">18</span><span class="p">)</span> <span class="p">(</span><span class="n">Scale</span> <span class="p">=</span> <span class="m">2</span><span class="p">),</span> <span class="n">@p45</span><span class="p">=</span><span class="err">'</span><span class="m">989</span><span class="err">'</span><span class="p">,</span> <span class="n">@p44</span><span class="p">=</span><span class="err">'</span><span class="m">10</span><span class="err">'</span> <span class="p">(</span><span class="n">Precision</span> <span class="p">=</span> <span class="m">18</span><span class="p">)</span> <span class="p">(</span><span class="n">Scale</span> <span class="p">=</span> <span class="m">2</span><span class="p">),</span> <span class="n">@p47</span><span class="p">=</span><span class="err">'</span><span class="m">990</span><span class="err">'</span><span class="p">,</span> <span class="n">@p46</span><span class="p">=</span><span class="err">'</span><span class="m">10</span><span class="err">'</span> <span class="p">(</span><span class="n">Precision</span> <span class="p">=</span> <span class="m">18</span><span class="p">)</span> <span class="p">(</span><span class="n">Scale</span> <span class="p">=</span> <span class="m">2</span><span class="p">),</span> <span class="n">@p49</span><span class="p">=</span><span class="err">'</span><span class="m">991</span><span class="err">'</span><span class="p">,</span> <span class="n">@p48</span><span class="p">=</span><span class="err">'</span><span class="m">10</span><span class="err">'</span> <span class="p">(</span><span class="n">Precision</span> <span class="p">=</span> <span class="m">18</span><span class="p">)</span> <span class="p">(</span><span class="n">Scale</span> <span class="p">=</span> <span class="m">2</span><span class="p">),</span> <span class="n">@p51</span><span class="p">=</span><span class="err">'</span><span class="m">992</span><span class="err">'</span><span class="p">,</span> <span class="n">@p50</span><span class="p">=</span><span class="err">'</span><span class="m">10</span><span class="err">'</span> <span class="p">(</span><span class="n">Precision</span> <span class="p">=</span> <span class="m">18</span><span class="p">)</span> <span class="p">(</span><span class="n">Scale</span> <span class="p">=</span> <span class="m">2</span><span class="p">),</span> <span class="n">@p53</span><span class="p">=</span><span class="err">'</span><span class="m">993</span><span class="err">'</span><span class="p">,</span> <span class="n">@p52</span><span class="p">=</span><span class="err">'</span><span class="m">10</span><span class="err">'</span> <span class="p">(</span><span class="n">Precision</span> <span class="p">=</span> <span class="m">18</span><span class="p">)</span> <span class="p">(</span><span class="n">Scale</span> <span class="p">=</span> <span class="m">2</span><span class="p">),</span> <span class="n">@p55</span><span class="p">=</span><span class="err">'</span><span class="m">994</span><span class="err">'</span><span class="p">,</span> <span class="n">@p54</span><span class="p">=</span><span class="err">'</span><span class="m">10</span><span class="err">'</span> <span class="p">(</span><span class="n">Precision</span> <span class="p">=</span> <span class="m">18</span><span class="p">)</span> <span class="p">(</span><span class="n">Scale</span> <span class="p">=</span> <span class="m">2</span><span class="p">),</span> <span class="n">@p57</span><span class="p">=</span><span class="err">'</span><span class="m">995</span><span class="err">'</span><span class="p">,</span> <span class="n">@p56</span><span class="p">=</span><span class="err">'</span><span class="m">10</span><span class="err">'</span> <span class="p">(</span><span class="n">Precision</span> <span class="p">=</span> <span class="m">18</span><span class="p">)</span> <span class="p">(</span><span class="n">Scale</span> <span class="p">=</span> <span class="m">2</span><span class="p">),</span> <span class="n">@p59</span><span class="p">=</span><span class="err">'</span><span class="m">996</span><span class="err">'</span><span class="p">,</span> <span class="n">@p58</span><span class="p">=</span><span class="err">'</span><span class="m">10</span><span class="err">'</span> <span class="p">(</span><span class="n">Precision</span> <span class="p">=</span> <span class="m">18</span><span class="p">)</span> <span class="p">(</span><span class="n">Scale</span> <span class="p">=</span> <span class="m">2</span><span class="p">),</span> <span class="n">@p61</span><span class="p">=</span><span class="err">'</span><span class="m">997</span><span class="err">'</span><span class="p">,</span> <span class="n">@p60</span><span class="p">=</span><span class="err">'</span><span class="m">10</span><span class="err">'</span> <span class="p">(</span><span class="n">Precision</span> <span class="p">=</span> <span class="m">18</span><span class="p">)</span> <span class="p">(</span><span class="n">Scale</span> <span class="p">=</span> <span class="m">2</span><span class="p">),</span> <span class="n">@p63</span><span class="p">=</span><span class="err">'</span><span class="m">998</span><span class="err">'</span><span class="p">,</span> <span class="n">@p62</span><span class="p">=</span><span class="err">'</span><span class="m">10</span><span class="err">'</span> <span class="p">(</span><span class="n">Precision</span> <span class="p">=</span> <span class="m">18</span><span class="p">)</span> <span class="p">(</span><span class="n">Scale</span> <span class="p">=</span> <span class="m">2</span><span class="p">),</span> <span class="n">@p65</span><span class="p">=</span><span class="err">'</span><span class="m">999</span><span class="err">'</span><span class="p">,</span> <span class="n">@p64</span><span class="p">=</span><span class="err">'</span><span class="m">10</span><span class="err">'</span> <span class="p">(</span><span class="n">Precision</span> <span class="p">=</span> <span class="m">18</span><span class="p">)</span> <span class="p">(</span><span class="n">Scale</span> <span class="p">=</span> <span class="m">2</span><span class="p">),</span> <span class="n">@p67</span><span class="p">=</span><span class="err">'</span><span class="m">1000</span><span class="err">'</span><span class="p">,</span> <span class="n">@p66</span><span class="p">=</span><span class="err">'</span><span class="m">10</span><span class="err">'</span> <span class="p">(</span><span class="n">Precision</span> <span class="p">=</span> <span class="m">18</span><span class="p">)</span> <span class="p">(</span><span class="n">Scale</span> <span class="p">=</span> <span class="m">2</span><span class="p">)],</span> <span class="n">CommandType</span><span class="p">=</span><span class="err">'</span><span class="n">Text</span><span class="err">'</span><span class="p">,</span> <span class="n">CommandTimeout</span><span class="p">=</span><span class="err">'</span><span class="m">30</span><span class="err">'</span><span class="p">]</span>
      <span class="n">SET</span> <span class="n">NOCOUNT</span> <span class="n">ON</span><span class="p">;</span>
      <span class="n">UPDATE</span> <span class="p">[</span><span class="n">People</span><span class="p">]</span> <span class="n">SET</span> <span class="p">[</span><span class="n">Discount</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p0</span>
      <span class="n">OUTPUT</span> <span class="m">1</span>
      <span class="n">WHERE</span> <span class="p">[</span><span class="n">Id</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p1</span><span class="p">;</span>
      <span class="n">UPDATE</span> <span class="p">[</span><span class="n">People</span><span class="p">]</span> <span class="n">SET</span> <span class="p">[</span><span class="n">Discount</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p2</span>
      <span class="n">OUTPUT</span> <span class="m">1</span>
      <span class="n">WHERE</span> <span class="p">[</span><span class="n">Id</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p3</span><span class="p">;</span>
      <span class="n">UPDATE</span> <span class="p">[</span><span class="n">People</span><span class="p">]</span> <span class="n">SET</span> <span class="p">[</span><span class="n">Discount</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p4</span>
      <span class="n">OUTPUT</span> <span class="m">1</span>
      <span class="n">WHERE</span> <span class="p">[</span><span class="n">Id</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p5</span><span class="p">;</span>
      <span class="n">UPDATE</span> <span class="p">[</span><span class="n">People</span><span class="p">]</span> <span class="n">SET</span> <span class="p">[</span><span class="n">Discount</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p6</span>
      <span class="n">OUTPUT</span> <span class="m">1</span>
      <span class="n">WHERE</span> <span class="p">[</span><span class="n">Id</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p7</span><span class="p">;</span>
      <span class="n">UPDATE</span> <span class="p">[</span><span class="n">People</span><span class="p">]</span> <span class="n">SET</span> <span class="p">[</span><span class="n">Discount</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p8</span>
      <span class="n">OUTPUT</span> <span class="m">1</span>
      <span class="n">WHERE</span> <span class="p">[</span><span class="n">Id</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p9</span><span class="p">;</span>
      <span class="n">UPDATE</span> <span class="p">[</span><span class="n">People</span><span class="p">]</span> <span class="n">SET</span> <span class="p">[</span><span class="n">Discount</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p10</span>
      <span class="n">OUTPUT</span> <span class="m">1</span>
      <span class="n">WHERE</span> <span class="p">[</span><span class="n">Id</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p11</span><span class="p">;</span>
      <span class="n">UPDATE</span> <span class="p">[</span><span class="n">People</span><span class="p">]</span> <span class="n">SET</span> <span class="p">[</span><span class="n">Discount</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p12</span>
      <span class="n">OUTPUT</span> <span class="m">1</span>
      <span class="n">WHERE</span> <span class="p">[</span><span class="n">Id</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p13</span><span class="p">;</span>
      <span class="n">UPDATE</span> <span class="p">[</span><span class="n">People</span><span class="p">]</span> <span class="n">SET</span> <span class="p">[</span><span class="n">Discount</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p14</span>
      <span class="n">OUTPUT</span> <span class="m">1</span>
      <span class="n">WHERE</span> <span class="p">[</span><span class="n">Id</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p15</span><span class="p">;</span>
      <span class="n">UPDATE</span> <span class="p">[</span><span class="n">People</span><span class="p">]</span> <span class="n">SET</span> <span class="p">[</span><span class="n">Discount</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p16</span>
      <span class="n">OUTPUT</span> <span class="m">1</span>
      <span class="n">WHERE</span> <span class="p">[</span><span class="n">Id</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p17</span><span class="p">;</span>
      <span class="n">UPDATE</span> <span class="p">[</span><span class="n">People</span><span class="p">]</span> <span class="n">SET</span> <span class="p">[</span><span class="n">Discount</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p18</span>
      <span class="n">OUTPUT</span> <span class="m">1</span>
      <span class="n">WHERE</span> <span class="p">[</span><span class="n">Id</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p19</span><span class="p">;</span>
      <span class="n">UPDATE</span> <span class="p">[</span><span class="n">People</span><span class="p">]</span> <span class="n">SET</span> <span class="p">[</span><span class="n">Discount</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p20</span>
      <span class="n">OUTPUT</span> <span class="m">1</span>
      <span class="n">WHERE</span> <span class="p">[</span><span class="n">Id</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p21</span><span class="p">;</span>
      <span class="n">UPDATE</span> <span class="p">[</span><span class="n">People</span><span class="p">]</span> <span class="n">SET</span> <span class="p">[</span><span class="n">Discount</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p22</span>
      <span class="n">OUTPUT</span> <span class="m">1</span>
      <span class="n">WHERE</span> <span class="p">[</span><span class="n">Id</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p23</span><span class="p">;</span>
      <span class="n">UPDATE</span> <span class="p">[</span><span class="n">People</span><span class="p">]</span> <span class="n">SET</span> <span class="p">[</span><span class="n">Discount</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p24</span>
      <span class="n">OUTPUT</span> <span class="m">1</span>
      <span class="n">WHERE</span> <span class="p">[</span><span class="n">Id</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p25</span><span class="p">;</span>
      <span class="n">UPDATE</span> <span class="p">[</span><span class="n">People</span><span class="p">]</span> <span class="n">SET</span> <span class="p">[</span><span class="n">Discount</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p26</span>
      <span class="n">OUTPUT</span> <span class="m">1</span>
      <span class="n">WHERE</span> <span class="p">[</span><span class="n">Id</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p27</span><span class="p">;</span>
      <span class="n">UPDATE</span> <span class="p">[</span><span class="n">People</span><span class="p">]</span> <span class="n">SET</span> <span class="p">[</span><span class="n">Discount</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p28</span>
      <span class="n">OUTPUT</span> <span class="m">1</span>
      <span class="n">WHERE</span> <span class="p">[</span><span class="n">Id</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p29</span><span class="p">;</span>
      <span class="n">UPDATE</span> <span class="p">[</span><span class="n">People</span><span class="p">]</span> <span class="n">SET</span> <span class="p">[</span><span class="n">Discount</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p30</span>
      <span class="n">OUTPUT</span> <span class="m">1</span>
      <span class="n">WHERE</span> <span class="p">[</span><span class="n">Id</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p31</span><span class="p">;</span>
      <span class="n">UPDATE</span> <span class="p">[</span><span class="n">People</span><span class="p">]</span> <span class="n">SET</span> <span class="p">[</span><span class="n">Discount</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p32</span>
      <span class="n">OUTPUT</span> <span class="m">1</span>
      <span class="n">WHERE</span> <span class="p">[</span><span class="n">Id</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p33</span><span class="p">;</span>
      <span class="n">UPDATE</span> <span class="p">[</span><span class="n">People</span><span class="p">]</span> <span class="n">SET</span> <span class="p">[</span><span class="n">Discount</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p34</span>
      <span class="n">OUTPUT</span> <span class="m">1</span>
      <span class="n">WHERE</span> <span class="p">[</span><span class="n">Id</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p35</span><span class="p">;</span>
      <span class="n">UPDATE</span> <span class="p">[</span><span class="n">People</span><span class="p">]</span> <span class="n">SET</span> <span class="p">[</span><span class="n">Discount</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p36</span>
      <span class="n">OUTPUT</span> <span class="m">1</span>
      <span class="n">WHERE</span> <span class="p">[</span><span class="n">Id</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p37</span><span class="p">;</span>
      <span class="n">UPDATE</span> <span class="p">[</span><span class="n">People</span><span class="p">]</span> <span class="n">SET</span> <span class="p">[</span><span class="n">Discount</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p38</span>
      <span class="n">OUTPUT</span> <span class="m">1</span>
      <span class="n">WHERE</span> <span class="p">[</span><span class="n">Id</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p39</span><span class="p">;</span>
      <span class="n">UPDATE</span> <span class="p">[</span><span class="n">People</span><span class="p">]</span> <span class="n">SET</span> <span class="p">[</span><span class="n">Discount</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p40</span>
      <span class="n">OUTPUT</span> <span class="m">1</span>
      <span class="n">WHERE</span> <span class="p">[</span><span class="n">Id</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p41</span><span class="p">;</span>
      <span class="n">UPDATE</span> <span class="p">[</span><span class="n">People</span><span class="p">]</span> <span class="n">SET</span> <span class="p">[</span><span class="n">Discount</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p42</span>
      <span class="n">OUTPUT</span> <span class="m">1</span>
      <span class="n">WHERE</span> <span class="p">[</span><span class="n">Id</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p43</span><span class="p">;</span>
      <span class="n">UPDATE</span> <span class="p">[</span><span class="n">People</span><span class="p">]</span> <span class="n">SET</span> <span class="p">[</span><span class="n">Discount</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p44</span>
      <span class="n">OUTPUT</span> <span class="m">1</span>
      <span class="n">WHERE</span> <span class="p">[</span><span class="n">Id</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p45</span><span class="p">;</span>
      <span class="n">UPDATE</span> <span class="p">[</span><span class="n">People</span><span class="p">]</span> <span class="n">SET</span> <span class="p">[</span><span class="n">Discount</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p46</span>
      <span class="n">OUTPUT</span> <span class="m">1</span>
      <span class="n">WHERE</span> <span class="p">[</span><span class="n">Id</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p47</span><span class="p">;</span>
      <span class="n">UPDATE</span> <span class="p">[</span><span class="n">People</span><span class="p">]</span> <span class="n">SET</span> <span class="p">[</span><span class="n">Discount</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p48</span>
      <span class="n">OUTPUT</span> <span class="m">1</span>
      <span class="n">WHERE</span> <span class="p">[</span><span class="n">Id</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p49</span><span class="p">;</span>
      <span class="n">UPDATE</span> <span class="p">[</span><span class="n">People</span><span class="p">]</span> <span class="n">SET</span> <span class="p">[</span><span class="n">Discount</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p50</span>
      <span class="n">OUTPUT</span> <span class="m">1</span>
      <span class="n">WHERE</span> <span class="p">[</span><span class="n">Id</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p51</span><span class="p">;</span>
      <span class="n">UPDATE</span> <span class="p">[</span><span class="n">People</span><span class="p">]</span> <span class="n">SET</span> <span class="p">[</span><span class="n">Discount</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p52</span>
      <span class="n">OUTPUT</span> <span class="m">1</span>
      <span class="n">WHERE</span> <span class="p">[</span><span class="n">Id</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p53</span><span class="p">;</span>
      <span class="n">UPDATE</span> <span class="p">[</span><span class="n">People</span><span class="p">]</span> <span class="n">SET</span> <span class="p">[</span><span class="n">Discount</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p54</span>
      <span class="n">OUTPUT</span> <span class="m">1</span>
      <span class="n">WHERE</span> <span class="p">[</span><span class="n">Id</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p55</span><span class="p">;</span>
      <span class="n">UPDATE</span> <span class="p">[</span><span class="n">People</span><span class="p">]</span> <span class="n">SET</span> <span class="p">[</span><span class="n">Discount</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p56</span>
      <span class="n">OUTPUT</span> <span class="m">1</span>
      <span class="n">WHERE</span> <span class="p">[</span><span class="n">Id</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p57</span><span class="p">;</span>
      <span class="n">UPDATE</span> <span class="p">[</span><span class="n">People</span><span class="p">]</span> <span class="n">SET</span> <span class="p">[</span><span class="n">Discount</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p58</span>
      <span class="n">OUTPUT</span> <span class="m">1</span>
      <span class="n">WHERE</span> <span class="p">[</span><span class="n">Id</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p59</span><span class="p">;</span>
      <span class="n">UPDATE</span> <span class="p">[</span><span class="n">People</span><span class="p">]</span> <span class="n">SET</span> <span class="p">[</span><span class="n">Discount</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p60</span>
      <span class="n">OUTPUT</span> <span class="m">1</span>
      <span class="n">WHERE</span> <span class="p">[</span><span class="n">Id</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p61</span><span class="p">;</span>
      <span class="n">UPDATE</span> <span class="p">[</span><span class="n">People</span><span class="p">]</span> <span class="n">SET</span> <span class="p">[</span><span class="n">Discount</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p62</span>
      <span class="n">OUTPUT</span> <span class="m">1</span>
      <span class="n">WHERE</span> <span class="p">[</span><span class="n">Id</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p63</span><span class="p">;</span>
      <span class="n">UPDATE</span> <span class="p">[</span><span class="n">People</span><span class="p">]</span> <span class="n">SET</span> <span class="p">[</span><span class="n">Discount</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p64</span>
      <span class="n">OUTPUT</span> <span class="m">1</span>
      <span class="n">WHERE</span> <span class="p">[</span><span class="n">Id</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p65</span><span class="p">;</span>
      <span class="n">UPDATE</span> <span class="p">[</span><span class="n">People</span><span class="p">]</span> <span class="n">SET</span> <span class="p">[</span><span class="n">Discount</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p66</span>
      <span class="n">OUTPUT</span> <span class="m">1</span>
      <span class="n">WHERE</span> <span class="p">[</span><span class="n">Id</span><span class="p">]</span> <span class="p">=</span> <span class="n">@p67</span><span class="p">;</span>
</code></pre></div></div>

<h2 id="resolvendo-o-problema">Resolvendo o problema</h2>
<div style="text-align: justify;">
O <b>EF Core 7</b> trouxe novos métodos de extensão que ajudam a resolver o problema apresentado anteriormente, ficou muito mais simples e extremamente rápido atualizar uma massa de registros, veja um exemplo:
</div>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">rowsAffected</span> <span class="p">=</span> <span class="k">await</span> <span class="n">db</span>
    <span class="p">.</span><span class="n">Customers</span>
    <span class="p">.</span><span class="nf">Where</span><span class="p">(</span><span class="n">p</span> <span class="p">=&gt;</span> <span class="n">p</span><span class="p">.</span><span class="n">State</span> <span class="p">==</span> <span class="s">"SP"</span><span class="p">)</span>
    <span class="p">.</span><span class="nf">ExecuteUpdateAsync</span><span class="p">(</span><span class="n">p</span> <span class="p">=&gt;</span> <span class="n">p</span><span class="p">.</span><span class="nf">SetProperty</span><span class="p">(</span><span class="n">x</span> <span class="p">=&gt;</span> <span class="n">x</span><span class="p">.</span><span class="n">Discount</span><span class="p">,</span> <span class="m">11</span><span class="n">m</span><span class="p">));</span>
</code></pre></div></div>
<p>A instrução SQL ficou muito mais simplificada além de não rastrear os objetos mais na memória, em alguns testes não tão científicos que fiz 
em minha maquina enquanto testava outras coisas como Minimal API vs MVC, eu obitve uma performance em mais de 500%, isso é uma melhoria fantástica.</p>
<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="k">UPDATE</span> <span class="p">[</span><span class="n">p</span><span class="p">]</span>
      <span class="k">SET</span> <span class="p">[</span><span class="n">p</span><span class="p">].[</span><span class="n">Discount</span><span class="p">]</span> <span class="o">=</span> <span class="mi">11</span><span class="p">.</span><span class="mi">0</span>
      <span class="k">FROM</span> <span class="p">[</span><span class="n">Customers</span><span class="p">]</span> <span class="k">AS</span> <span class="p">[</span><span class="n">p</span><span class="p">]</span>
      <span class="k">WHERE</span> <span class="p">[</span><span class="n">p</span><span class="p">].[</span><span class="k">State</span><span class="p">]</span> <span class="o">=</span> <span class="n">N</span><span class="s1">'SP'</span>
</code></pre></div></div>
<p><br /></p>
<h2 id="métodos-de-extensão-novos">Métodos de extensão novos</h2>
<ul>
  <li>ExecuteUpdate</li>
  <li>ExecuteUpdateAsync</li>
  <li>ExecuteDelete</li>
  <li>ExecuteDeleteAsync</li>
</ul>

<p>Para excluir registros em massa você pode executar o seguinte comando:</p>
<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">var</span> <span class="n">rowsAffected</span> <span class="o">=</span> <span class="n">await</span> <span class="n">db</span>
    <span class="p">.</span><span class="n">Customers</span>
    <span class="p">.</span><span class="k">Where</span><span class="p">(</span><span class="n">p</span> <span class="o">=&gt;</span> <span class="n">p</span><span class="p">.</span><span class="k">State</span> <span class="o">==</span> <span class="nv">"SP"</span><span class="p">)</span>
    <span class="p">.</span><span class="n">ExecuteDeleteAsync</span><span class="p">();</span>
</code></pre></div></div>
<p>O comando executado na base de dados basicamente é mesmo que um humano escreveria.</p>
<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">DELETE</span> <span class="k">FROM</span> <span class="p">[</span><span class="n">p</span><span class="p">]</span>
      <span class="k">FROM</span> <span class="p">[</span><span class="n">People</span><span class="p">]</span> <span class="k">AS</span> <span class="p">[</span><span class="n">p</span><span class="p">]</span>
      <span class="k">WHERE</span> <span class="p">[</span><span class="n">p</span><span class="p">].[</span><span class="k">State</span><span class="p">]</span> <span class="o">=</span> <span class="n">N</span><span class="s1">'SP'</span>
</code></pre></div></div>
<p>Todos os métodos novos de extensão devolve a quantidade de registros que foram afetados na base de dados.</p>
<h2 id="contatos">Contatos</h2>
<div class="notice--info">
 Fico por aqui, mas pode me contatar por meio de minhas redes sociais 😄 <br />
 twitter: <a alt="" href="https://twitter.com/RalmsDeveloper">@ralmsdeveloper</a><br />
 linkedin: <a alt="" href="https://www.linkedin.com/in/ralmsdeveloper/">@ralmsdeveloper</a><br />
</div>]]></content><author><name>Rafael Almeida</name><email>ralms@ralms.net</email></author><category term="dotnet" /><category term="performance" /><category term="Entity Framework Core" /><category term="Entity Framework Core 7" /><summary type="html"><![CDATA[Este pequeno post é pra comemorar o lançamento do Entity Framework Core 7 e algumas observações pessoais, fiz alguns teses enquanto testava a performance de Minimal API vs MVC, e obtive mais 500% de performance com as novas features, isso é simplesmente fantástico! Introdução O Team do EF Core tem se dedicado bastante a melhorar o produto desde sua reescrita e lançamento oficial em 2016, todos ou quase todos sabem que o ORM foi reescrito 100% do zero, dado que a arquitetura anterior já impedia grandes evoluções no produto. A cada versão do produto geralmente costumamos ver diversas features sendo implementadas no produto, sendo que na versão EF Core 6 e agora o EF Core 7 não contém tantas features como costumávamos a ver, isso tem um motivo, o produto está ficando cada vez mais maduro e estável, além disso foco tem sido em melhorias de performance e features já existentes. A versão do EF Core 7 foi lançada oficialmente no 8 de novembro de 2022, ela não trouxe diversas novidades, mas trouxe algumas extremantes valiosas que são: Suporte JSON nativo Insert mais rápido Suporte atualização em massa Suporte exclusão em massa Atualização em massa Estarei focando aqui na atualização e exclusão em massa, dado que temos um ganho significativo de performance, vale lembrar que existem outras formas de atingir praticamente o mesmo objetivo que será apresentado, porém era workaround nada nativo do ORM. A atualização e exclusão em massa foi um dos tópicos mais comentados e solicitados no github do projeto, inclusive o próprio team do EF Core fez uma apresentação onde disponibilizou um gráfico de performance e os ganhos que tivemos desde o EF 6, chegando a ser 44x mais rápido com as novas features implementadas. Fonte imagens: PPT do Team EF Core Entendendo o problema Quando a gente precisava excluir ou atualizar uma massa de registros e existia a necessidade de aplicar um filtro para que as modificações fosse restrita apenas a um conjunto de dados, tínhamos que executar uma instrução bruta fora do capô do ORM ou consultar os dados via ORM para que os objetos fossem traqueados, executar a lógica desejada exclusão ou atualização do objeto e depois chamar o método SaveChanges, vamos pegar exemplo hipotético aqui de atualização de desconto para todos clientes do estado de São Paulo, a gente usava algo assim: var customers = db.Customers.Where(p =&gt; p.State == "SP"); foreach (var customer in customers) { customer.Discount = 10m; } db.SaveChanges(); Isso era o que a gente tinha para o momento, mas o custo de CPU e memória era muito alto, a instrução para atualização em massa era muito ruim dado que era gerado um comando para cada objeto afetado pela aplicação, veja um exemplo: [Parameters=[@p1='967', @p0='10' (Precision = 18) (Scale = 2), @p3='968', @p2='10' (Precision = 18) (Scale = 2), @p5='969', @p4='10' (Precision = 18) (Scale = 2), @p7='970', @p6='10' (Precision = 18) (Scale = 2), @p9='971', @p8='10' (Precision = 18) (Scale = 2), @p11='972', @p10='10' (Precision = 18) (Scale = 2), @p13='973', @p12='10' (Precision = 18) (Scale = 2), @p15='974', @p14='10' (Precision = 18) (Scale = 2), @p17='975', @p16='10' (Precision = 18) (Scale = 2), @p19='976', @p18='10' (Precision = 18) (Scale = 2), @p21='977', @p20='10' (Precision = 18) (Scale = 2), @p23='978', @p22='10' (Precision = 18) (Scale = 2), @p25='979', @p24='10' (Precision = 18) (Scale = 2), @p27='980', @p26='10' (Precision = 18) (Scale = 2), @p29='981', @p28='10' (Precision = 18) (Scale = 2), @p31='982', @p30='10' (Precision = 18) (Scale = 2), @p33='983', @p32='10' (Precision = 18) (Scale = 2), @p35='984', @p34='10' (Precision = 18) (Scale = 2), @p37='985', @p36='10' (Precision = 18) (Scale = 2), @p39='986', @p38='10' (Precision = 18) (Scale = 2), @p41='987', @p40='10' (Precision = 18) (Scale = 2), @p43='988', @p42='10' (Precision = 18) (Scale = 2), @p45='989', @p44='10' (Precision = 18) (Scale = 2), @p47='990', @p46='10' (Precision = 18) (Scale = 2), @p49='991', @p48='10' (Precision = 18) (Scale = 2), @p51='992', @p50='10' (Precision = 18) (Scale = 2), @p53='993', @p52='10' (Precision = 18) (Scale = 2), @p55='994', @p54='10' (Precision = 18) (Scale = 2), @p57='995', @p56='10' (Precision = 18) (Scale = 2), @p59='996', @p58='10' (Precision = 18) (Scale = 2), @p61='997', @p60='10' (Precision = 18) (Scale = 2), @p63='998', @p62='10' (Precision = 18) (Scale = 2), @p65='999', @p64='10' (Precision = 18) (Scale = 2), @p67='1000', @p66='10' (Precision = 18) (Scale = 2)], CommandType='Text', CommandTimeout='30'] SET NOCOUNT ON; UPDATE [People] SET [Discount] = @p0 OUTPUT 1 WHERE [Id] = @p1; UPDATE [People] SET [Discount] = @p2 OUTPUT 1 WHERE [Id] = @p3; UPDATE [People] SET [Discount] = @p4 OUTPUT 1 WHERE [Id] = @p5; UPDATE [People] SET [Discount] = @p6 OUTPUT 1 WHERE [Id] = @p7; UPDATE [People] SET [Discount] = @p8 OUTPUT 1 WHERE [Id] = @p9; UPDATE [People] SET [Discount] = @p10 OUTPUT 1 WHERE [Id] = @p11; UPDATE [People] SET [Discount] = @p12 OUTPUT 1 WHERE [Id] = @p13; UPDATE [People] SET [Discount] = @p14 OUTPUT 1 WHERE [Id] = @p15; UPDATE [People] SET [Discount] = @p16 OUTPUT 1 WHERE [Id] = @p17; UPDATE [People] SET [Discount] = @p18 OUTPUT 1 WHERE [Id] = @p19; UPDATE [People] SET [Discount] = @p20 OUTPUT 1 WHERE [Id] = @p21; UPDATE [People] SET [Discount] = @p22 OUTPUT 1 WHERE [Id] = @p23; UPDATE [People] SET [Discount] = @p24 OUTPUT 1 WHERE [Id] = @p25; UPDATE [People] SET [Discount] = @p26 OUTPUT 1 WHERE [Id] = @p27; UPDATE [People] SET [Discount] = @p28 OUTPUT 1 WHERE [Id] = @p29; UPDATE [People] SET [Discount] = @p30 OUTPUT 1 WHERE [Id] = @p31; UPDATE [People] SET [Discount] = @p32 OUTPUT 1 WHERE [Id] = @p33; UPDATE [People] SET [Discount] = @p34 OUTPUT 1 WHERE [Id] = @p35; UPDATE [People] SET [Discount] = @p36 OUTPUT 1 WHERE [Id] = @p37; UPDATE [People] SET [Discount] = @p38 OUTPUT 1 WHERE [Id] = @p39; UPDATE [People] SET [Discount] = @p40 OUTPUT 1 WHERE [Id] = @p41; UPDATE [People] SET [Discount] = @p42 OUTPUT 1 WHERE [Id] = @p43; UPDATE [People] SET [Discount] = @p44 OUTPUT 1 WHERE [Id] = @p45; UPDATE [People] SET [Discount] = @p46 OUTPUT 1 WHERE [Id] = @p47; UPDATE [People] SET [Discount] = @p48 OUTPUT 1 WHERE [Id] = @p49; UPDATE [People] SET [Discount] = @p50 OUTPUT 1 WHERE [Id] = @p51; UPDATE [People] SET [Discount] = @p52 OUTPUT 1 WHERE [Id] = @p53; UPDATE [People] SET [Discount] = @p54 OUTPUT 1 WHERE [Id] = @p55; UPDATE [People] SET [Discount] = @p56 OUTPUT 1 WHERE [Id] = @p57; UPDATE [People] SET [Discount] = @p58 OUTPUT 1 WHERE [Id] = @p59; UPDATE [People] SET [Discount] = @p60 OUTPUT 1 WHERE [Id] = @p61; UPDATE [People] SET [Discount] = @p62 OUTPUT 1 WHERE [Id] = @p63; UPDATE [People] SET [Discount] = @p64 OUTPUT 1 WHERE [Id] = @p65; UPDATE [People] SET [Discount] = @p66 OUTPUT 1 WHERE [Id] = @p67; Resolvendo o problema O EF Core 7 trouxe novos métodos de extensão que ajudam a resolver o problema apresentado anteriormente, ficou muito mais simples e extremamente rápido atualizar uma massa de registros, veja um exemplo: var rowsAffected = await db .Customers .Where(p =&gt; p.State == "SP") .ExecuteUpdateAsync(p =&gt; p.SetProperty(x =&gt; x.Discount, 11m)); A instrução SQL ficou muito mais simplificada além de não rastrear os objetos mais na memória, em alguns testes não tão científicos que fiz em minha maquina enquanto testava outras coisas como Minimal API vs MVC, eu obitve uma performance em mais de 500%, isso é uma melhoria fantástica. UPDATE [p] SET [p].[Discount] = 11.0 FROM [Customers] AS [p] WHERE [p].[State] = N'SP' Métodos de extensão novos ExecuteUpdate ExecuteUpdateAsync ExecuteDelete ExecuteDeleteAsync Para excluir registros em massa você pode executar o seguinte comando: var rowsAffected = await db .Customers .Where(p =&gt; p.State == "SP") .ExecuteDeleteAsync(); O comando executado na base de dados basicamente é mesmo que um humano escreveria. DELETE FROM [p] FROM [People] AS [p] WHERE [p].[State] = N'SP' Todos os métodos novos de extensão devolve a quantidade de registros que foram afetados na base de dados. Contatos Fico por aqui, mas pode me contatar por meio de minhas redes sociais 😄 twitter: @ralmsdeveloper linkedin: @ralmsdeveloper]]></summary></entry><entry><title type="html">EF Core 8 Preview 1 - DateOnly</title><link href="http://old-blog.ralms.io/dotnet/entity%20framework%20core/entity%20framework%20core%208/raw-sql-ef-core-8-preview-dateonly-1/" rel="alternate" type="text/html" title="EF Core 8 Preview 1 - DateOnly" /><published>2023-02-27T00:00:00-03:00</published><updated>2023-02-27T00:00:00-03:00</updated><id>http://old-blog.ralms.io/dotnet/entity%20framework%20core/entity%20framework%20core%208/raw-sql-ef-core-8-preview-dateonly-1</id><content type="html" xml:base="http://old-blog.ralms.io/dotnet/entity%20framework%20core/entity%20framework%20core%208/raw-sql-ef-core-8-preview-dateonly-1/"><![CDATA[<p><img src="http://old-blog.ralms.io/assets/images/2023/ef_core_8_preview_1_dateonly.png" alt="01" /></p>
<hr />

<div class="notice--warning" style="background-color:#f8ffc4">
Esse é meu lugar especial onde adoro compartilhar novidades e pensamentos sobre .NET, Performance e Acesso a Dados com a comunidade.
</div>

<h2 id="introdução">Introdução</h2>
<div style="text-align: justify;">
Quando a Microsoft lançou o Entity Framework Core 8 além de tantas outras funcionalidades, ganhamos também mais um recurso interessante, o qual não precisamos ficar criando conversores, falo isso porque o EF Core fornece essa possibilidade.
<br /><br />
Bom, a novidade é o DateOnly e TimeOnly, que são tipos que foram lançados lá na versão do .NET 6 e que inclusive vários outro provedores de acesso a dados já tinham implementado, como por exemplo o de acesso ao PostgreSQL, e aí fica a pergunta porque o EF Core levou mais tempo para implementar esse recurso, bom a resposta é simples, como o EF Core para SQL Server tem uma forte dependência com o driver de acesso ao SQL Server, primeiramente seria necessário aguardar que o time de desenvolvimento do driver adicionasse esses novos tipos no driver.
<br /><br />
Então agora é possível utilizar esses novos tipos com o EF Core 8, veja um exemplo simples.
</div>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">Alarme</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="kt">int</span> <span class="n">Id</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">Descricao</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">};</span>
    <span class="k">public</span> <span class="n">DateOnly</span> <span class="n">Data</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="n">TimeOnly</span> <span class="n">Hora</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<div style="text-align: justify;">
Ao fazer o mapeamento desse entidade, quando o EF Core gerar o script para criar a tabela no banco de dados basicamente teremos o seguinte script:
</div>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">CREATE</span> <span class="k">TABLE</span> <span class="p">[</span><span class="n">Alarmes</span><span class="p">]</span> <span class="p">(</span>
    <span class="p">[</span><span class="n">Id</span><span class="p">]</span> <span class="nb">int</span> <span class="k">NOT</span> <span class="k">NULL</span> <span class="k">IDENTITY</span><span class="p">,</span>
    <span class="p">[</span><span class="n">Descricao</span><span class="p">]</span> <span class="n">nvarchar</span><span class="p">(</span><span class="k">max</span><span class="p">)</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span>
    <span class="p">[</span><span class="k">Data</span><span class="p">]</span> <span class="nb">date</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span>
    <span class="p">[</span><span class="n">Hora</span><span class="p">]</span> <span class="nb">time</span>  <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span>
    <span class="k">CONSTRAINT</span> <span class="p">[</span><span class="n">PK_Alarmes</span><span class="p">]</span> <span class="k">PRIMARY</span> <span class="k">KEY</span> <span class="p">([</span><span class="n">Id</span><span class="p">]));</span>
</code></pre></div></div>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">DateOnly</span> <span class="n">data</span> <span class="p">=</span> <span class="n">DateOnly</span><span class="p">.</span><span class="nf">Parse</span><span class="p">(</span><span class="s">"2023-01-01"</span><span class="p">);</span>
<span class="n">TimeOnly</span> <span class="n">hora</span> <span class="p">=</span> <span class="n">TimeOnly</span><span class="p">.</span><span class="nf">Parse</span><span class="p">(</span><span class="s">"01:01:01"</span><span class="p">);</span>

<span class="kt">var</span> <span class="n">alarme</span> <span class="p">=</span> <span class="n">context</span>
    <span class="p">.</span><span class="n">Alarmes</span>
    <span class="p">.</span><span class="nf">FirstOrDefault</span><span class="p">(</span><span class="n">p</span><span class="p">=&gt;</span> <span class="n">p</span><span class="p">.</span><span class="n">Data</span> <span class="p">==</span> <span class="n">data</span> <span class="p">&amp;&amp;</span> <span class="n">p</span><span class="p">.</span><span class="n">Hora</span> <span class="p">==</span> <span class="n">hora</span><span class="p">);</span> 

</code></pre></div></div>
<div style="text-align: justify;">
Pra quem utiliza o SQL Server e armazena dados do tipo date ou time, essa é uma funcionalidade bem interessante!
</div>
<h2 id="contatos">Contatos</h2>
<div class="notice--info">
 Fico por aqui, mas pode me contatar por meio de minhas redes sociais 😄 <br />
 twitter: <a alt="" href="https://twitter.com/RalmsDeveloper">@ralmsdeveloper</a><br />
 linkedin: <a alt="" href="https://www.linkedin.com/in/ralmsdeveloper/">@ralmsdeveloper</a><br />
</div>]]></content><author><name>Rafael Almeida</name><email>ralms@ralms.net</email></author><category term="dotnet" /><category term="Entity Framework Core" /><category term="Entity Framework Core 8" /><summary type="html"><![CDATA[Esse é meu lugar especial onde adoro compartilhar novidades e pensamentos sobre .NET, Performance e Acesso a Dados com a comunidade. Introdução Quando a Microsoft lançou o Entity Framework Core 8 além de tantas outras funcionalidades, ganhamos também mais um recurso interessante, o qual não precisamos ficar criando conversores, falo isso porque o EF Core fornece essa possibilidade. Bom, a novidade é o DateOnly e TimeOnly, que são tipos que foram lançados lá na versão do .NET 6 e que inclusive vários outro provedores de acesso a dados já tinham implementado, como por exemplo o de acesso ao PostgreSQL, e aí fica a pergunta porque o EF Core levou mais tempo para implementar esse recurso, bom a resposta é simples, como o EF Core para SQL Server tem uma forte dependência com o driver de acesso ao SQL Server, primeiramente seria necessário aguardar que o time de desenvolvimento do driver adicionasse esses novos tipos no driver. Então agora é possível utilizar esses novos tipos com o EF Core 8, veja um exemplo simples. public class Alarme { public int Id { get; set; } public string Descricao { get; set; }; public DateOnly Data { get; set; } public TimeOnly Hora { get; set; } } Ao fazer o mapeamento desse entidade, quando o EF Core gerar o script para criar a tabela no banco de dados basicamente teremos o seguinte script: CREATE TABLE [Alarmes] ( [Id] int NOT NULL IDENTITY, [Descricao] nvarchar(max) NOT NULL, [Data] date NOT NULL, [Hora] time NOT NULL, CONSTRAINT [PK_Alarmes] PRIMARY KEY ([Id])); DateOnly data = DateOnly.Parse("2023-01-01"); TimeOnly hora = TimeOnly.Parse("01:01:01"); var alarme = context .Alarmes .FirstOrDefault(p=&gt; p.Data == data &amp;&amp; p.Hora == hora); Pra quem utiliza o SQL Server e armazena dados do tipo date ou time, essa é uma funcionalidade bem interessante! Contatos Fico por aqui, mas pode me contatar por meio de minhas redes sociais 😄 twitter: @ralmsdeveloper linkedin: @ralmsdeveloper]]></summary></entry><entry><title type="html">EF Core 8 Preview 1 - News</title><link href="http://old-blog.ralms.io/dotnet/entity%20framework%20core/entity%20framework%20core%208/raw-sql-ef-core-8-preview-1/" rel="alternate" type="text/html" title="EF Core 8 Preview 1 - News" /><published>2023-02-23T00:00:00-03:00</published><updated>2023-02-23T00:00:00-03:00</updated><id>http://old-blog.ralms.io/dotnet/entity%20framework%20core/entity%20framework%20core%208/raw-sql-ef-core-8-preview-1</id><content type="html" xml:base="http://old-blog.ralms.io/dotnet/entity%20framework%20core/entity%20framework%20core%208/raw-sql-ef-core-8-preview-1/"><![CDATA[<p><img src="http://old-blog.ralms.io/assets/images/2023/ef_core_8_preview_1_raw.png" alt="01" /></p>
<hr />

<div class="notice--warning" style="background-color:#f8ffc4">
Esse é meu lugar especial para compartilhar novidades e pensamentos sobre tecnologia com a comunidade.
</div>

<h2 id="introdução">Introdução</h2>
<div style="text-align: justify;">
A Microsoft tem feito muito pela comunidade de desenvolvedores com projetos open source, o qual sinto orgulho de participar contribuindo em alguns deles como o Entity Framework Core, ele tem se tornado um projeto muito interessante por meio da dedicação dos engenheiros da Microsoft e por inúmeras contribuições da comunidade de forma global.
<br /><br />
Nesse último preview lançado do produto podemos agora escrever consultas sem necessidade de criar um modelo de dados e configurar no bom e velho DbContext. Sim, é possível agora escrever consultas da mesma “forma” como fazemos utilizando o Dapper.
<br /><br />
Para comunidade isso é muito importante, dado que em muitos casos queremos utilizar todos recursos do EF Core, mas escrevendo consultas independentes, vamos ver como isso ficou.
<br />
</div>

<div style="text-align: justify;">
Para executar comandos no banco de dados como por exemplo atualizar um registro ou criar tabela já tinhamos essa funcionalidade que era o <b>ExecuteSql</b>:
</div>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">context</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">MeuContexto</span><span class="p">();</span>
<span class="n">context</span><span class="p">.</span><span class="n">Database</span><span class="p">.</span><span class="nf">ExecuteSql</span><span class="p">(</span><span class="err">@</span><span class="s">$"CREATE TABLE ...."</span><span class="p">);</span>
<span class="n">context</span><span class="p">.</span><span class="n">Database</span><span class="p">.</span><span class="nf">ExecuteSql</span><span class="p">(</span><span class="err">@</span><span class="s">$"UPDATE TABLE ...."</span><span class="p">);</span>
</code></pre></div></div>
<div style="text-align: justify;">
Até aqui tudo bem certo?! Vamos agora para a parte da consulta, pra ver como podemos fazer consultas sem necessidade de fazer um mapeamento no EF Core, basicamente iremos utilizar o novo método chamado <b>SqlQuery</b>, vamos para o exemplo:
</div>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">Artigo</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="kt">int</span> <span class="n">Id</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">Titulo</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>

<span class="kt">var</span> <span class="n">artigos</span> <span class="p">=</span>
    <span class="k">await</span> <span class="n">context</span><span class="p">.</span><span class="n">Database</span>
        <span class="p">.</span><span class="n">SqlQuery</span><span class="p">&lt;</span><span class="n">Artigo</span><span class="p">&gt;(</span><span class="s">$"SELECT TOP 12 * FROM Artigos ORDER BY id DESC"</span><span class="p">)</span>
        <span class="p">.</span><span class="nf">ToListAsync</span><span class="p">();</span>
</code></pre></div></div>
<div style="text-align: justify;">
 Bom de forma bem simples é isso, basta você ter uma classe com os campos que corresponde a seus campos no banco de dados e executar sua consulta,
 o EF Core irá fazer o discovery das propriedades e mapear para você.
</div>
<h2 id="contatos">Contatos</h2>
<div class="notice--info">
 Fico por aqui, mas pode me contatar por meio de minhas redes sociais 😄 <br />
 twitter: <a alt="" href="https://twitter.com/RalmsDeveloper">@ralmsdeveloper</a><br />
 linkedin: <a alt="" href="https://www.linkedin.com/in/ralmsdeveloper/">@ralmsdeveloper</a><br />
</div>]]></content><author><name>Rafael Almeida</name><email>ralms@ralms.net</email></author><category term="dotnet" /><category term="Entity Framework Core" /><category term="Entity Framework Core 8" /><summary type="html"><![CDATA[Esse é meu lugar especial para compartilhar novidades e pensamentos sobre tecnologia com a comunidade. Introdução A Microsoft tem feito muito pela comunidade de desenvolvedores com projetos open source, o qual sinto orgulho de participar contribuindo em alguns deles como o Entity Framework Core, ele tem se tornado um projeto muito interessante por meio da dedicação dos engenheiros da Microsoft e por inúmeras contribuições da comunidade de forma global. Nesse último preview lançado do produto podemos agora escrever consultas sem necessidade de criar um modelo de dados e configurar no bom e velho DbContext. Sim, é possível agora escrever consultas da mesma “forma” como fazemos utilizando o Dapper. Para comunidade isso é muito importante, dado que em muitos casos queremos utilizar todos recursos do EF Core, mas escrevendo consultas independentes, vamos ver como isso ficou. Para executar comandos no banco de dados como por exemplo atualizar um registro ou criar tabela já tinhamos essa funcionalidade que era o ExecuteSql: var context = new MeuContexto(); context.Database.ExecuteSql(@$"CREATE TABLE ...."); context.Database.ExecuteSql(@$"UPDATE TABLE ...."); Até aqui tudo bem certo?! Vamos agora para a parte da consulta, pra ver como podemos fazer consultas sem necessidade de fazer um mapeamento no EF Core, basicamente iremos utilizar o novo método chamado SqlQuery, vamos para o exemplo: public class Artigo { public int Id { get; set; } public string Titulo { get; set; } } var artigos = await context.Database .SqlQuery&lt;Artigo&gt;($"SELECT TOP 12 * FROM Artigos ORDER BY id DESC") .ToListAsync(); Bom de forma bem simples é isso, basta você ter uma classe com os campos que corresponde a seus campos no banco de dados e executar sua consulta, o EF Core irá fazer o discovery das propriedades e mapear para você. Contatos Fico por aqui, mas pode me contatar por meio de minhas redes sociais 😄 twitter: @ralmsdeveloper linkedin: @ralmsdeveloper]]></summary></entry><entry><title type="html">Criando validações mais performaticas</title><link href="http://old-blog.ralms.io/dotnet/performance/otimizacao-sem-regex/" rel="alternate" type="text/html" title="Criando validações mais performaticas" /><published>2022-10-25T00:00:00-03:00</published><updated>2022-10-25T00:00:00-03:00</updated><id>http://old-blog.ralms.io/dotnet/performance/otimizacao-sem-regex</id><content type="html" xml:base="http://old-blog.ralms.io/dotnet/performance/otimizacao-sem-regex/"><![CDATA[<p><img src="http://old-blog.ralms.io/assets/images/2022/otimizacao_sem_regex.png" alt="01" /></p>
<hr />

<div class="notice--warning" style="background-color:#f8ffc4">
Esse é meu lugar especial onde adoro compartilhar novidades e pensamentos sobre .NET, Performance e Acesso a Dados com a comunidade.
</div>

<h2 id="introdução">Introdução</h2>
<div style="text-align: justify;">
Já falei muito sobre performance em várias oportunidades que tive, palestrando ou discussões técnicas com amigos e profissionais do mercado, e tem uma frase que utilizo bastante que é “Não é sobre reinventar a roda, é simplesmente sobre não usar Regex pra tudo!”. Parece clichê, mas isso é uma pura verdade.
<br /><br />
O Regex é sem sombra de dúvidas um recurso extremamente importante na vida de nós desenvolvedores, porque podemos fazer muitas validações de forma simples com ele, más em muitos cenários não existe a necessidade de sua utilização, pode parecer otimizações prematuras, mas sempre que puder melhorar a performance de suas aplicações com códigos que não tragam complexidade pra você ou seu time, escreva-o!!!
<br /><br />
Vamos pegar aqui um cenários hipotético, mas pode ser aplicado em outros cenários, se você precisar fazer algumas validações como por exemplo verificar se em uma string contém números, você não precisa usar REGEX, você pode simplesmente digitar umas 4 linhas de código e deixar suas validações milhares de vezes mais rápida, vamos para um exemplo, para isso criei uma classe com alguns métodos usando regex compilado e interpretado, também criei um método chamado "MetodoCustomizado" para validar sua performance.
</div>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">[</span><span class="nf">SimpleJob</span><span class="p">(</span><span class="n">RuntimeMoniker</span><span class="p">.</span><span class="n">Net70</span><span class="p">,</span> <span class="n">baseline</span><span class="p">:</span> <span class="k">true</span><span class="p">)]</span>
<span class="p">[</span><span class="n">MemoryDiagnoser</span><span class="p">]</span>
<span class="p">[</span><span class="nf">HideColumns</span><span class="p">(</span><span class="s">"Error"</span><span class="p">,</span> <span class="s">"StdDev"</span><span class="p">,</span> <span class="s">"Median"</span><span class="p">,</span> <span class="s">"RatioSD"</span><span class="p">,</span> <span class="s">"Ratio"</span><span class="p">)]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">VerificarSeExisteNumerosEmUmaString</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">static</span> <span class="kt">string</span> <span class="n">_nome</span> <span class="p">=</span> <span class="s">"Rafael 012345679 Santos"</span><span class="p">;</span>
    <span class="k">public</span> <span class="k">static</span> <span class="n">Regex</span> <span class="n">_regexCompilado</span> <span class="p">=</span> <span class="k">new</span> <span class="p">(</span><span class="s">"[0-9]"</span><span class="p">,</span> <span class="n">RegexOptions</span><span class="p">.</span><span class="n">Compiled</span><span class="p">);</span>

    <span class="p">[</span><span class="n">Benchmark</span><span class="p">]</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">RegexInterpretado</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">regex</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">Regex</span><span class="p">(</span><span class="s">"[0-9]"</span><span class="p">);</span>
        <span class="n">_</span> <span class="p">=</span> <span class="n">regex</span><span class="p">.</span><span class="nf">IsMatch</span><span class="p">(</span><span class="n">_nome</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="p">[</span><span class="n">Benchmark</span><span class="p">]</span>
    <span class="k">public</span> <span class="k">void</span> <span class="nf">RegexCompilado</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="n">_</span> <span class="p">=</span> <span class="n">_regexCompilado</span><span class="p">.</span><span class="nf">IsMatch</span><span class="p">(</span><span class="n">_nome</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="p">[</span><span class="n">Benchmark</span><span class="p">]</span>
    <span class="k">public</span> <span class="kt">bool</span> <span class="nf">MetodoCustomizado</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">span</span> <span class="p">=</span> <span class="n">_nome</span><span class="p">.</span><span class="nf">AsSpan</span><span class="p">();</span>

        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="p">=</span> <span class="m">0</span><span class="p">;</span> <span class="n">i</span> <span class="p">&lt;</span> <span class="n">span</span><span class="p">.</span><span class="n">Length</span><span class="p">;</span> <span class="n">i</span><span class="p">++)</span>
        <span class="p">{</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">span</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="p">&gt;=</span> <span class="sc">'0'</span> <span class="p">&amp;&amp;</span> <span class="n">span</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="p">&lt;=</span> <span class="sc">'9'</span><span class="p">)</span>
                <span class="k">return</span> <span class="k">true</span><span class="p">;</span>
        <span class="p">}</span>

        <span class="k">return</span> <span class="k">false</span><span class="p">;</span>
    <span class="p">}</span> 
<span class="p">}</span>
</code></pre></div></div>
<div style="text-align: justify;">
Ao executar o Benchmark fica claro que nosso método customizado é extremamente muito mais rápido, com 3.395 ns.
</div>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// * Summary *</span>
<span class="n">BenchmarkDotNet</span><span class="p">=</span><span class="n">v0</span><span class="p">.</span><span class="m">13.2</span><span class="p">,</span> <span class="n">OS</span><span class="p">=</span><span class="n">Windows</span> <span class="m">11</span> <span class="p">(</span><span class="m">10.0</span><span class="p">.</span><span class="m">22000.1219</span><span class="p">/</span><span class="m">21</span><span class="n">H2</span><span class="p">)</span>
<span class="n">Intel</span> <span class="n">Core</span> <span class="n">i9</span><span class="p">-</span><span class="m">10900</span><span class="n">K</span> <span class="n">CPU</span> <span class="m">3.70</span><span class="n">GHz</span><span class="p">,</span> <span class="m">1</span> <span class="n">CPU</span><span class="p">,</span> <span class="m">20</span> <span class="n">logical</span> <span class="n">and</span> <span class="m">10</span> <span class="n">physical</span> <span class="n">cores</span>
<span class="p">.</span><span class="n">NET</span> <span class="n">SDK</span><span class="p">=</span><span class="m">7.0</span><span class="p">.</span><span class="m">100</span>
  <span class="p">[</span><span class="n">Host</span><span class="p">]</span>   <span class="p">:</span> <span class="p">.</span><span class="n">NET</span> <span class="m">6.0</span><span class="p">.</span><span class="m">9</span> <span class="p">(</span><span class="m">6.0</span><span class="p">.</span><span class="m">922.41905</span><span class="p">),</span> <span class="n">X64</span> <span class="n">RyuJIT</span> <span class="n">AVX2</span>
  <span class="p">.</span><span class="n">NET</span> <span class="m">7.0</span> <span class="p">:</span> <span class="p">.</span><span class="n">NET</span> <span class="m">7.0</span><span class="p">.</span><span class="m">0</span> <span class="p">(</span><span class="m">7.0</span><span class="p">.</span><span class="m">22.51805</span><span class="p">),</span> <span class="n">X64</span> <span class="n">RyuJIT</span> <span class="n">AVX2</span>

<span class="n">Job</span><span class="p">=.</span><span class="n">NET</span> <span class="m">7.0</span>  <span class="n">Runtime</span><span class="p">=.</span><span class="n">NET</span> <span class="m">7.0</span>  

<span class="p">|</span>            <span class="n">Method</span> <span class="p">|</span>       <span class="n">Mean</span> <span class="p">|</span>      <span class="n">Error</span> <span class="p">|</span>     <span class="n">StdDev</span> <span class="p">|</span>     <span class="n">Median</span> <span class="p">|</span> <span class="n">Ratio</span> <span class="p">|</span>   <span class="n">Gen0</span> <span class="p">|</span> <span class="n">Allocated</span> <span class="p">|</span> <span class="n">Alloc</span> <span class="n">Ratio</span> <span class="p">|</span>
<span class="p">|------------------</span> <span class="p">|-----------:|-----------:|-----------:|-----------:|------:|-------:|----------:|------------:|</span>
<span class="p">|</span> <span class="n">RegexInterpretado</span> <span class="p">|</span> <span class="m">812.431</span> <span class="n">ns</span> <span class="p">|</span> <span class="m">14.2141</span> <span class="n">ns</span> <span class="p">|</span> <span class="m">26.6975</span> <span class="n">ns</span> <span class="p">|</span> <span class="m">801.174</span> <span class="n">ns</span> <span class="p">|</span>  <span class="m">1.00</span> <span class="p">|</span> <span class="m">0.2308</span> <span class="p">|</span>    <span class="m">2432</span> <span class="n">B</span> <span class="p">|</span>        <span class="m">1.00</span> <span class="p">|</span>
<span class="p">|</span>    <span class="n">RegexCompilado</span> <span class="p">|</span>  <span class="m">30.091</span> <span class="n">ns</span> <span class="p">|</span>  <span class="m">0.0435</span> <span class="n">ns</span> <span class="p">|</span>  <span class="m">0.0407</span> <span class="n">ns</span> <span class="p">|</span>  <span class="m">30.071</span> <span class="n">ns</span> <span class="p">|</span>  <span class="m">1.00</span> <span class="p">|</span>      <span class="p">-</span> <span class="p">|</span>         <span class="p">-</span> <span class="p">|</span>          <span class="n">NA</span> <span class="p">|</span>
<span class="p">|</span> <span class="n">MetodoCustomizado</span> <span class="p">|</span>   <span class="m">3.395</span> <span class="n">ns</span> <span class="p">|</span>  <span class="m">0.0167</span> <span class="n">ns</span> <span class="p">|</span>  <span class="m">0.0148</span> <span class="n">ns</span> <span class="p">|</span>   <span class="m">3.392</span> <span class="n">ns</span> <span class="p">|</span>  <span class="m">1.00</span> <span class="p">|</span>      <span class="p">-</span> <span class="p">|</span>         <span class="p">-</span> <span class="p">|</span>          <span class="n">NA</span> <span class="p">|</span>

</code></pre></div></div>
<div style="text-align: justify;">
Reflexão, como falei no inicio do post, sempre que você for fazer otimizações como essa, verifique se não está adicionando complexidade que você não precisa, 
mas eu sou do time que sempre que pode escrever mais bits para melhorar a performance, estarei escrevendo!
</div>
<h2 id="contatos">Contatos</h2>
<div class="notice--info">
 Fico por aqui, mas pode me contatar por meio de minhas redes sociais 😄 <br />
 twitter: <a alt="" href="https://twitter.com/RalmsDeveloper">@ralmsdeveloper</a><br />
 linkedin: <a alt="" href="https://www.linkedin.com/in/ralmsdeveloper/">@ralmsdeveloper</a><br />
</div>]]></content><author><name>Rafael Almeida</name><email>ralms@ralms.net</email></author><category term="dotnet" /><category term="Performance" /><summary type="html"><![CDATA[Esse é meu lugar especial onde adoro compartilhar novidades e pensamentos sobre .NET, Performance e Acesso a Dados com a comunidade. Introdução Já falei muito sobre performance em várias oportunidades que tive, palestrando ou discussões técnicas com amigos e profissionais do mercado, e tem uma frase que utilizo bastante que é “Não é sobre reinventar a roda, é simplesmente sobre não usar Regex pra tudo!”. Parece clichê, mas isso é uma pura verdade. O Regex é sem sombra de dúvidas um recurso extremamente importante na vida de nós desenvolvedores, porque podemos fazer muitas validações de forma simples com ele, más em muitos cenários não existe a necessidade de sua utilização, pode parecer otimizações prematuras, mas sempre que puder melhorar a performance de suas aplicações com códigos que não tragam complexidade pra você ou seu time, escreva-o!!! Vamos pegar aqui um cenários hipotético, mas pode ser aplicado em outros cenários, se você precisar fazer algumas validações como por exemplo verificar se em uma string contém números, você não precisa usar REGEX, você pode simplesmente digitar umas 4 linhas de código e deixar suas validações milhares de vezes mais rápida, vamos para um exemplo, para isso criei uma classe com alguns métodos usando regex compilado e interpretado, também criei um método chamado "MetodoCustomizado" para validar sua performance. [SimpleJob(RuntimeMoniker.Net70, baseline: true)] [MemoryDiagnoser] [HideColumns("Error", "StdDev", "Median", "RatioSD", "Ratio")] public class VerificarSeExisteNumerosEmUmaString { public static string _nome = "Rafael 012345679 Santos"; public static Regex _regexCompilado = new ("[0-9]", RegexOptions.Compiled); [Benchmark] public void RegexInterpretado() { var regex = new Regex("[0-9]"); _ = regex.IsMatch(_nome); } [Benchmark] public void RegexCompilado() { _ = _regexCompilado.IsMatch(_nome); } [Benchmark] public bool MetodoCustomizado() { var span = _nome.AsSpan(); for (int i = 0; i &lt; span.Length; i++) { if (span[i] &gt;= '0' &amp;&amp; span[i] &lt;= '9') return true; } return false; } } Ao executar o Benchmark fica claro que nosso método customizado é extremamente muito mais rápido, com 3.395 ns. // * Summary * BenchmarkDotNet=v0.13.2, OS=Windows 11 (10.0.22000.1219/21H2) Intel Core i9-10900K CPU 3.70GHz, 1 CPU, 20 logical and 10 physical cores .NET SDK=7.0.100 [Host] : .NET 6.0.9 (6.0.922.41905), X64 RyuJIT AVX2 .NET 7.0 : .NET 7.0.0 (7.0.22.51805), X64 RyuJIT AVX2 Job=.NET 7.0 Runtime=.NET 7.0 | Method | Mean | Error | StdDev | Median | Ratio | Gen0 | Allocated | Alloc Ratio | |------------------ |-----------:|-----------:|-----------:|-----------:|------:|-------:|----------:|------------:| | RegexInterpretado | 812.431 ns | 14.2141 ns | 26.6975 ns | 801.174 ns | 1.00 | 0.2308 | 2432 B | 1.00 | | RegexCompilado | 30.091 ns | 0.0435 ns | 0.0407 ns | 30.071 ns | 1.00 | - | - | NA | | MetodoCustomizado | 3.395 ns | 0.0167 ns | 0.0148 ns | 3.392 ns | 1.00 | - | - | NA | Reflexão, como falei no inicio do post, sempre que você for fazer otimizações como essa, verifique se não está adicionando complexidade que você não precisa, mas eu sou do time que sempre que pode escrever mais bits para melhorar a performance, estarei escrevendo! Contatos Fico por aqui, mas pode me contatar por meio de minhas redes sociais 😄 twitter: @ralmsdeveloper linkedin: @ralmsdeveloper]]></summary></entry><entry><title type="html">Melhorar legibilidade do código (AND &amp;amp; OR)</title><link href="http://old-blog.ralms.io/dotnet/dicas/dica-melhorar-legibilidade-com-novos-operadores-logicos/" rel="alternate" type="text/html" title="Melhorar legibilidade do código (AND &amp;amp; OR)" /><published>2022-05-07T00:00:00-03:00</published><updated>2022-05-07T00:00:00-03:00</updated><id>http://old-blog.ralms.io/dotnet/dicas/dica-melhorar-legibilidade-com-novos-operadores-logicos</id><content type="html" xml:base="http://old-blog.ralms.io/dotnet/dicas/dica-melhorar-legibilidade-com-novos-operadores-logicos/"><![CDATA[<p><img src="http://old-blog.ralms.io/assets/images/2022/legibilidade_and_or.png" alt="01" /></p>
<hr />

<div class="notice--warning" style="background-color:#f8ffc4">
Durante o processo de desenvolvimento de um sistema sempre nos esforçamos para escrever códigos melhores, e, na dica de hoje irei apresentar um recurso do C# 9 fantástico.
</div>

<h2 id="introdução">Introdução</h2>
<div style="text-align: justify;">
Sabemos que a linguagem C#/.NET está em um processo contínuo de evolução, a cada versão recursos novos surgem e são bastante agregadores para o ciclo de desenvolvimento de nossas aplicações, na dica de hoje irei apresentar operador lógico que podemos combinar com expressões para validar uma determinada entrada de dados, vamos pegar como exemplo hipotético a validação de uma cadeia de caracteres e verificar se existe letras maiúsculas ou números, veja o exemplo abaixo:
<br />
</div>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">bool</span> <span class="nf">Exists</span><span class="p">(</span><span class="kt">char</span> <span class="n">letter</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">(</span><span class="n">letter</span> <span class="p">&gt;=</span> <span class="sc">'0'</span> <span class="p">&amp;&amp;</span> <span class="n">letter</span> <span class="p">&lt;=</span> <span class="sc">'9'</span><span class="p">)</span> <span class="p">||</span> <span class="p">(</span><span class="n">letter</span> <span class="p">&gt;=</span> <span class="sc">'A'</span> <span class="p">&amp;&amp;</span> <span class="n">letter</span> <span class="p">&lt;=</span> <span class="sc">'Z'</span><span class="p">);</span>
</code></pre></div></div>
<p>Bom me parece que isso é bem simples concorda?<br />
Como podemos melhorar isso?</p>
<h2 id="novo-recurso-do-c-90">Novo recurso do C# 9.0</h2>
<div style="text-align: justify;">
A Microsoft lança o C# 9.0 com recursos bem legais como os operados <b>AND</b> e <b>OR</b> que podem simplificar muito mais seus códigos, vamos ver um exemplo simples 
de refatoração do código criado acima..
</div>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">bool</span> <span class="nf">Exists</span><span class="p">(</span><span class="kt">char</span> <span class="n">letter</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="n">letter</span> <span class="k">is</span> <span class="p">(&gt;=</span> <span class="sc">'0'</span> <span class="n">and</span> <span class="p">&lt;=</span> <span class="sc">'9'</span><span class="p">)</span> <span class="nf">or</span> <span class="p">(&gt;=</span> <span class="sc">'A'</span> <span class="n">and</span> <span class="p">&lt;=</span> <span class="sc">'Z'</span><span class="p">);</span>
</code></pre></div></div>
<div style="text-align: justify;">
A mudança foi muito simples néh?! Porém conseguimos simplificar ainda mais nosso código, uma dica é que você não precisa entrar no hype, mas é importante conhecer esses novos recursos e analisar como podem lhe ajudar em seu dia a dia.
</div>
<h2 id="contatos">Contatos</h2>
<div class="notice--info">
 Fico por aqui, mas pode me contatar por meio de minhas redes sociais 😄 <br />
 twitter: <a alt="" href="https://twitter.com/RalmsDeveloper">@ralmsdeveloper</a><br />
 linkedin: <a alt="" href="https://www.linkedin.com/in/ralmsdeveloper/">@ralmsdeveloper</a><br />
</div>]]></content><author><name>Rafael Almeida</name><email>ralms@ralms.net</email></author><category term="dotnet" /><category term="Dicas" /><summary type="html"><![CDATA[Durante o processo de desenvolvimento de um sistema sempre nos esforçamos para escrever códigos melhores, e, na dica de hoje irei apresentar um recurso do C# 9 fantástico. Introdução Sabemos que a linguagem C#/.NET está em um processo contínuo de evolução, a cada versão recursos novos surgem e são bastante agregadores para o ciclo de desenvolvimento de nossas aplicações, na dica de hoje irei apresentar operador lógico que podemos combinar com expressões para validar uma determinada entrada de dados, vamos pegar como exemplo hipotético a validação de uma cadeia de caracteres e verificar se existe letras maiúsculas ou números, veja o exemplo abaixo: bool Exists(char letter) =&gt; (letter &gt;= '0' &amp;&amp; letter &lt;= '9') || (letter &gt;= 'A' &amp;&amp; letter &lt;= 'Z'); Bom me parece que isso é bem simples concorda? Como podemos melhorar isso? Novo recurso do C# 9.0 A Microsoft lança o C# 9.0 com recursos bem legais como os operados AND e OR que podem simplificar muito mais seus códigos, vamos ver um exemplo simples de refatoração do código criado acima.. bool Exists(char letter) =&gt; letter is (&gt;= '0' and &lt;= '9') or (&gt;= 'A' and &lt;= 'Z'); A mudança foi muito simples néh?! Porém conseguimos simplificar ainda mais nosso código, uma dica é que você não precisa entrar no hype, mas é importante conhecer esses novos recursos e analisar como podem lhe ajudar em seu dia a dia. Contatos Fico por aqui, mas pode me contatar por meio de minhas redes sociais 😄 twitter: @ralmsdeveloper linkedin: @ralmsdeveloper]]></summary></entry></feed>