<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Mauricio Redmerski André</title>
    <description>The latest articles on DEV Community by Mauricio Redmerski André (@mauricio-andre).</description>
    <link>https://dev.to/mauricio-andre</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1012311%2Ff5c8dc13-5982-421e-9a09-56027a7b064c.jpeg</url>
      <title>DEV Community: Mauricio Redmerski André</title>
      <link>https://dev.to/mauricio-andre</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mauricio-andre"/>
    <language>en</language>
    <item>
      <title>gRPC: um panorama do contexto histórico às aplicações práticas!</title>
      <dc:creator>Mauricio Redmerski André</dc:creator>
      <pubDate>Sun, 20 Oct 2024 18:36:29 +0000</pubDate>
      <link>https://dev.to/becomex/grpc-um-panorama-do-contexto-historico-as-aplicacoes-praticas-4j2l</link>
      <guid>https://dev.to/becomex/grpc-um-panorama-do-contexto-historico-as-aplicacoes-praticas-4j2l</guid>
      <description>&lt;p&gt;Olá, pessoal. Tudo bem?&lt;/p&gt;

&lt;p&gt;Há algum tempo, desenvolvi um conteúdo sobre gRPC para criar um bootcamp e disseminar este conhecimento entre os times de software da Becomex. Embora o modelo de bootcamp não tenha sido implementado na prática, o material ficou excelente. Por isso, decidi transformar a parte teórica em um post e compartilhar esse conteúdo com a comunidade.&lt;/p&gt;

&lt;p&gt;Para aprender qualquer coisa na vida, começar pelo básico é sempre uma ótima ideia. Antes de mergulharmos no gRPC, vamos entender o que é RPC e o caminho que nos trouxe até aqui. Neste artigo, você terá uma breve introdução aos conceitos de RPC, a diferença básica entre RPC e REST, e entenderá por que o gRPC é tão rápido e uma excelente alternativa para a transição de grandes volumes de dados. Além disso, vamos apresentar exemplos de implementação para facilitar o entendimento.&lt;br&gt;
Então, ajeite-se na cadeira e prepare sua garrafa d'água, porque vem muita informação boa por aí!&lt;/p&gt;
&lt;h2&gt;
  
  
  A origem
&lt;/h2&gt;

&lt;p&gt;O RPC ou &lt;em&gt;Remote Procedure Call&lt;/em&gt; (chamada de processo remoto em português) é uma técnica que permite realizar a chamada de uma função de forma remota. Com o RPC, o recurso &lt;strong&gt;A&lt;/strong&gt; solicita a execução de uma função ao recurso &lt;strong&gt;B&lt;/strong&gt;, estes podem ser componentes distintos que compõem um grande circuito, ou computadores conectados em rede, mostrando que esse modelo de comunicação não está vinculado somente ao protocolo HTTP, mas também se aplicando facilmente a outros protocolos de comunicação.&lt;/p&gt;

&lt;p&gt;As proposições teóricas de modelos de chamadas remotas em redes de computadores começaram a ser feitas na década de 70, tendo como marco importante a publicação da &lt;a href="https://www.rfc-editor.org/rfc/rfc707" rel="noopener noreferrer"&gt;RFC 707&lt;/a&gt; no final do ano de 1975 e no começo do ano de 1976 sob o título &lt;em&gt;A High-Level Framework for Network-Based Resource Sharing&lt;/em&gt;. Esse documento, dentre outras coisas, enfatizou a necessidade de padronização dos protocolos de comunicação entre sistemas.&lt;/p&gt;

&lt;p&gt;O primeiro uso comercial do modelo de comunicação RPC ocorreu em um projeto desenvolvido pela Xerox PARC em 1981. Foi durante esse período que o termo RPC teria sido cunhado por Bruce Jay Nelson, um dos cientistas da computação da empresa.&lt;/p&gt;

&lt;p&gt;Anos mais tarde, o Google criou sua própria arquitetura RPC. Essa infraestrutura de propósito geral chamada Stubby foi utilizada por mais de uma década para conectar o vasto número de microsserviços operando dentro e entre seus data centers. Como afirmado pela própria Google, o Stubby possuía vários recursos excelentes, mas estava altamente acoplado à sua infraestrutura interna para ser considerado adequado para o lançamento ao público. Em 2015, a Google publica então o gRPC, um projeto de código aberto que nasce como a evolução do Stubby.&lt;/p&gt;

&lt;p&gt;Ao contrário do que muitas pessoas podem pensar, o "g" em gRPC não significa Google. Na realidade, a cada nova versão lançada do gRPC, o "g" é ressignificado. &lt;a href="https://github.com/grpc/grpc/blob/master/doc/g_stands_for.md?ref=blog.lsantos.dev" rel="noopener noreferrer"&gt;Clique aqui&lt;/a&gt; e confira a lista de nomes atribuídos ao “g”. Para todos os efeitos, podemos entender o termo gRPC como &lt;em&gt;high performance Remote Procedure Call&lt;/em&gt; ou chamada de processo remoto de alta performance no nosso bom português.&lt;/p&gt;
&lt;h2&gt;
  
  
  Diferença entre RPC e REST
&lt;/h2&gt;

&lt;p&gt;O modelo REST &lt;em&gt;Representational State Transfer&lt;/em&gt; é potencialmente o mais popular atualmente, e a maioria das APIs web com que trabalhamos são REST ou pseudo REST. Por isso, parece ser uma boa ideia explicar como o RPC funciona comparando-o a um modelo mais conhecido.&lt;/p&gt;

&lt;p&gt;Fundamentalmente, o REST expõe os recursos ou entidades de sua aplicação e usa os métodos HTTP para fornecer significado semântico às ações realizadas. Já o RPC expõe as operações que a aplicação pode realizar e, em geral, usa apenas dois diferentes métodos HTTP (quando a comunicação se dá por esse protocolo).&lt;/p&gt;

&lt;p&gt;Em uma API REST, se você desejar expor dados sobre usuários, você provavelmente teria o seguinte cenário:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET api/v1/users
GET api/v1/users/:id
POST api/v1/users
PUT api/v1/users/:id
DELETE api/v1/users/:id
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Em uma API RPC, ao invés de expor uma rota de usuários e usar os métodos HTTP para atribuir significado às operações, cada rota se parecerá como uma função específica. Veja o exemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET api/v1/getUserList
GET api/v1/getUserById
POST api/v1/createUser
POST api/v1/updateUser
POST api/v1/deleteUser
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cada modelo de comunicação oferece diferentes níveis de facilidade para representar as operações de uma aplicação. O REST, por exemplo, é ideal para operações de CRUD (criar, ler, atualizar, deletar), enquanto o RPC é mais eficiente para executar ações da sua aplicação, como enviar e-mails ou realizar cálculos. No entanto, nada impede que o RPC seja usado para operações de CRUD, assim como o REST pode ser aplicado para executar funções em uma API.&lt;/p&gt;

&lt;h2&gt;
  
  
  De onde vem o &lt;em&gt;high performance&lt;/em&gt; do gRPC?
&lt;/h2&gt;

&lt;p&gt;A essa altura, você já deve ter percebido que o gRPC nada mais é do que a implementação de um modelo de API RPC, construído de modo a fornecer um alto desempenho em suas execuções. Mas como esse alto desempenho é construído? A primeira coisa que precisamos entender é que o gRPC não é uma tecnologia em si, mas uma junção de várias técnicas e tecnologias. Bora explorar cada uma delas?&lt;/p&gt;

&lt;h3&gt;
  
  
  Execução sob o protocolo de comunicação HTTP/2
&lt;/h3&gt;

&lt;p&gt;Implementar uma API gRPC significa utilizar o protocolo HTTP/2 para estabelecer a conexão e a troca de informação entre o cliente e o servidor. O HTTP/2 que também foi criado pelo Google oferece vários recursos de melhoria de desempenho em relação ao seu antecessor. Aqui, vamos explorar duas de suas principais características, mas você pode ter uma leitura completa consultando a &lt;a href="https://www.rfc-editor.org/rfc/rfc7540" rel="noopener noreferrer"&gt;RFC 7540&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Stream e Multiplexação
&lt;/h4&gt;

&lt;p&gt;Uma das principais limitações do HTTP/1.1 é a sua restrição no envio e recebimento de dados. Nesta versão, não é possível enviar ou receber mais de uma mensagem por conexão, o que significa que, se você precisar enviar duas mensagens ao servidor, terá que abrir duas conexões separadas. Isso torna o processo mais lento, já que a cada requisição é necessário refazer o &lt;em&gt;handshake&lt;/em&gt; com o servidor e reenviar eventuais informações repetitivas entre as requisições. Além disso, por questões de desempenho, o número de conexões simultâneas que um browser pode fazer com um servidor é limitado. Para entender melhor essa limitação, recomendo o artigo &lt;a href="https://ishwar-rimal.medium.com/why-does-your-browser-limit-the-number-of-concurrent-network-calls-1ae5d50863dd" rel="noopener noreferrer"&gt;Why does your browser limit the number of concurrent network calls?&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;O protocolo HTTP/2, por outro lado, permite algo chamado multiplexação, o que significa que é possível enviar mais de uma requisição ao servidor por meio de uma única conexão. Isso resolve as limitações de conexões simultâneas e os tempos de &lt;em&gt;handshake&lt;/em&gt; que a versão anterior impunha. A imagem abaixo, retirada do livro &lt;em&gt;HTTP/2 in Action&lt;/em&gt;, ilustra de forma simples esse funcionamento.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzz993u6zxr6qmaepuoqe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzz993u6zxr6qmaepuoqe.png" alt="Comparação entre http/1.1 e http/2" width="800" height="503"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Compressão e redução dos headers
&lt;/h4&gt;

&lt;p&gt;Outra característica interessante do HTTP/2 é a compressão dos &lt;em&gt;headers&lt;/em&gt; das mensagens. Em alguns casos, os &lt;em&gt;headers&lt;/em&gt; de uma requisição podem ser maiores que o próprio &lt;em&gt;payload&lt;/em&gt;, e o HTTP/2 faz uma compressão eficiente dessas informações. Além disso, como essa versão mantém uma única conexão para várias solicitações, não é necessário reenviar todos os &lt;em&gt;headers&lt;/em&gt; em cada requisição. O HTTP/2 apenas retransmite os &lt;em&gt;headers&lt;/em&gt; que foram alterados e, para os que permanecem iguais, envia apenas um índice de referência.&lt;/p&gt;

&lt;h3&gt;
  
  
  Protocol Buffers
&lt;/h3&gt;

&lt;p&gt;O Protocol Buffers (ou Protobuf, para os íntimos) é um método muito eficiente de serialização de dados. O Protobuf usa uma linguagem de definição de interface (IDL) para descrever arquivos agnósticos de plataformas e linguagens de programação. Esses arquivos contêm as especificações dos contratos e funções que o servidor pode fornecer e tanto o cliente quanto o servidor mantêm uma cópia desses arquivos, o que garante a coesão na troca de informações. Além disso, isso separa o contexto das mensagens trocadas na rede do seu conteúdo, diferentemente de contratos em JSON, onde contexto e conteúdo são enviados necessariamente juntos.&lt;/p&gt;

&lt;p&gt;Veja o exemplo abaixo, que utiliza a IDL do Protobuf para descrever um contrato de um objeto que representa um produto, com as propriedades &lt;em&gt;partnumber&lt;/em&gt;, que significam o código e a quantidade de um produto:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;syntax = "proto3";

message Produto {
  string partnumber = 1;
  int32 quantidade = 2;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Na primeira linha, definimos a sintaxe "proto3". Na terceira, declaramos uma mensagem (ou objeto) chamada "Produto", que pode ser usada tanto como entrada quanto saída de uma função. As linhas quatro e cinco definem as propriedades desse objeto, indicando o tipo, nome e índice de cada uma. E aqui está o interessante: nós definimos índices que determinam a posição das propriedades, o que significa que a mensagem enviada via gRPC não precisa carregar o nome da propriedade, apenas seu índice.&lt;/p&gt;

&lt;p&gt;Para ilustrar de forma mais clara, veja o exemplo em JSON que seria necessário para representar essa mensagem:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"partnumber"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Boinas"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"quantidade"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cada caractere da mensagem acima precisa ser transmitido pela rede por meio físico do servidor até o cliente. Quanto maior a mensagem, mais tempo levará para ser transmitida. O Protobuf codifica essa mesma mensagem em um conjunto muito menor de dados, o que acelera a transmissão pela rede. A codificação dessa mensagem pelo Protobuf seria a seguinte: &lt;code&gt;0A06426F696E6173109601&lt;/code&gt;. Não se preocupe, vou explicar como chegamos a esse valor em breve 😉. E ainda, graças ao HTTP/2, esses dados serão comprimidos antes de serem transmitidos.&lt;/p&gt;

&lt;p&gt;O Protobuf, que também foi criado pelo Google, pode ser usado de forma independente, sem estar necessariamente no contexto do gRPC. Se salvarmos o exemplo anterior em um arquivo chamado &lt;code&gt;Produto.proto&lt;/code&gt;, podemos rodar o seguinte comando no terminal: &lt;code&gt;echo 'partnumber: "boinas"; quantidade: 150' | protoc --encode=Produto produto.proto &amp;gt; produto.bin&lt;/code&gt; (você precisará instalar o &lt;a href="https://grpc.io/docs/protoc-installation/?ref=blog.lsantos.dev" rel="noopener noreferrer"&gt;protoc&lt;/a&gt; para isso). O comando &lt;code&gt;echo&lt;/code&gt; indica que queremos imprimir um conteúdo, o texto entre aspas simples é o conteúdo que queremos imprimir, concatenamos essa impressão com a chamada do &lt;code&gt;protoc&lt;/code&gt; indicando que queremos fazer o encode do objeto "Produto" &lt;code&gt;--encode=Produto&lt;/code&gt; especificado dentro do arquivo &lt;code&gt;produto.proto&lt;/code&gt;, por fim definimos que o resultado deve ser salvo dentro do arquivo &lt;code&gt;produto.bin&lt;/code&gt;. Para visualizar arquivos com essa codificação, gosto de usar o VS Code com a extensão &lt;a href="https://marketplace.visualstudio.com/items?itemName=ms-vscode.hexeditor" rel="noopener noreferrer"&gt;Hex Editor&lt;/a&gt;. É assim que você verá a sequência de caracteres &lt;code&gt;0A06426F696E6173109601&lt;/code&gt; mencionada anteriormente.&lt;/p&gt;

&lt;p&gt;O resultado gerado por essa operação é uma sequência hexadecimal, onde cada par de caracteres representa um conjunto de 8 bits. Vamos dar uma olhada mais detalhada nessa estrutura.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb1usyz0oxszed1l5nb8p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb1usyz0oxszed1l5nb8p.png" alt="Decomposição da sequência hexadecimal" width="800" height="340"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;O primeiro bit de cada par é o &lt;em&gt;most significant bit&lt;/em&gt; (MSB), ou continuation bit. Essa é uma estratégia inteligente de codificação para indicar se o próximo par faz parte da mesma representação de dado ou se é um dado separado. Quando o valor é 0, o par contém toda a informação. Se for 1, é necessário combinar os bits com o próximo par para interpretar o dado.&lt;/p&gt;

&lt;p&gt;Os pares &lt;strong&gt;0A&lt;/strong&gt; e &lt;strong&gt;10&lt;/strong&gt;, destacados em vermelho na imagem, representam as definições das propriedades enviadas. Após o primeiro bit (MSB), os próximos 4 bits indicam o índice da propriedade (lembrando que no arquivo .proto definimos índices representados aqui), e os três bits seguintes destacados em negrito indicam o tipo da mensagem.&lt;/p&gt;

&lt;p&gt;O par &lt;strong&gt;06&lt;/strong&gt;, destacado em azul, indica o comprimento da mensagem de texto (neste caso, 6 conjuntos), sempre que o tipo do dado for uma string, o dado será precedido por um ou mais conjuntos que definem o comprimento do texto transmitido na propriedade. Em seguida, destacado em cinza, temos a mensagem "Boinas", codificada.&lt;/p&gt;

&lt;p&gt;Os últimos dois conjuntos, &lt;strong&gt;96&lt;/strong&gt; e &lt;strong&gt;01&lt;/strong&gt;, representam o valor da propriedade "quantidade". Sabemos que devemos interpretar os dois pares juntos porque o primeiro par, &lt;strong&gt;96&lt;/strong&gt;, possui o valor 1 no MSB. Para interpretar um valor numérico serializado pelo Protobuf, removemos o MSB da sequência e aplicamos a técnica &lt;em&gt;little-endian&lt;/em&gt;, ordenando os bits menos significativos à frente. Isso resulta na sequência &lt;em&gt;10010110&lt;/em&gt;, que representa o valor 150 que informamos em nossa mensagem de teste.&lt;/p&gt;

&lt;p&gt;Se quiser entender mais sobre o processo de codificação do Protobuf, você pode consultar as especificações &lt;a href="https://protobuf.dev/programming-guides/encoding/" rel="noopener noreferrer"&gt;aqui&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Sintaxe e tipos padrões
&lt;/h4&gt;

&lt;p&gt;Já vimos um pouco da sintaxe da IDL do Protobuf nos exemplos anteriores, mas vamos nos aprofundar em alguns conceitos básicos.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight protobuf"&gt;&lt;code&gt;&lt;span class="na"&gt;syntax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"proto3"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;service&lt;/span&gt; &lt;span class="n"&gt;DocumentoService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;rpc&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ListDocumentoRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;returns&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="n"&gt;ListDocumentoResponse&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;message&lt;/span&gt; &lt;span class="nc"&gt;ListDocumentoRequest&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;reserved&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;int64&lt;/span&gt; &lt;span class="na"&gt;analise_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;optional&lt;/span&gt; &lt;span class="kt"&gt;int32&lt;/span&gt; &lt;span class="na"&gt;tipo_documento&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;optional&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="na"&gt;cnpj_participante&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;message&lt;/span&gt; &lt;span class="nc"&gt;ListDocumentoResponse&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;Documento&lt;/span&gt; &lt;span class="na"&gt;documento&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;message&lt;/span&gt; &lt;span class="nc"&gt;Documento&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;int64&lt;/span&gt; &lt;span class="na"&gt;documentoId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="na"&gt;chave_eletronica&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="na"&gt;valido&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="na"&gt;cnpj_emitente&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;repeated&lt;/span&gt; &lt;span class="na"&gt;Produto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;message&lt;/span&gt; &lt;span class="nc"&gt;Produto&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="na"&gt;partnumber&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;doubel&lt;/span&gt; &lt;span class="na"&gt;valor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No exemplo acima, usamos o termo service para indicar que estamos descrevendo as funções de um serviço chamado &lt;code&gt;DocumentoService&lt;/code&gt;. Em seguida, usamos o termo &lt;code&gt;rpc&lt;/code&gt; para descrever as funções que esse serviço suporta. Definimos uma função chamada &lt;code&gt;List&lt;/code&gt;, que recebe um objeto &lt;code&gt;ListDocumentoRequest&lt;/code&gt; e retorna um &lt;em&gt;stream&lt;/em&gt; de dados chamado &lt;code&gt;ListDocumentoResponse&lt;/code&gt;. O uso de &lt;em&gt;stream&lt;/em&gt; indica que o volume de dados pode ser alto, permitindo que o cliente processe os dados de forma parcial conforme o servidor os envia.&lt;/p&gt;

&lt;p&gt;Nosso exemplo continua com a definição da estrutura do objeto &lt;code&gt;ListDocumentoRequest&lt;/code&gt;. Nele, especificamos que a posição de índice 3 é &lt;code&gt;reserved&lt;/code&gt;, o que significa que nenhuma propriedade pode ocupar essa posição. A posição 3 não tem nada de especial, foi apenas uma escolha para demonstrar essa possibilidade. Também definimos uma propriedade chamada &lt;code&gt;analise_id&lt;/code&gt; como &lt;code&gt;int64&lt;/code&gt;, e as duas propriedades seguintes são marcadas com o termo &lt;code&gt;optional&lt;/code&gt;. Isso significa que, ao transmitir a mensagem, podemos omitir esses dois parâmetros.&lt;/p&gt;

&lt;p&gt;Um ponto importante a se observar ao definir propriedades como &lt;code&gt;optional&lt;/code&gt; no Protobuf é que, ao fazer isso, habilitamos uma propriedade chamada &lt;code&gt;Has{MinhaVariável}&lt;/code&gt; no objeto convertido para a nossa linguagem de programação. Antes de acessar a propriedade &lt;code&gt;optional&lt;/code&gt;, é essencial verificar se essa propriedade está marcada como &lt;code&gt;true&lt;/code&gt; ou &lt;code&gt;false&lt;/code&gt;. Se tentarmos recuperar a propriedade diretamente, sem essa verificação, receberemos o valor padrão do tipo de dado em questão (0 para inteiros e vazio para strings por exemplo).&lt;/p&gt;

&lt;p&gt;Veja um exemplo em C# de como recuperar esses dados:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;DocumentoFilter&lt;/span&gt; &lt;span class="nf"&gt;MapToFilter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ListDocumentoRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;DocumentoFilter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;AnaliseId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AnaliseId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;TipoDocumento&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HasTipoDocumento&lt;/span&gt;
      &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TipoDocumento&lt;/span&gt;
      &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;CnpjParticipante&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CnpjParticipante&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Antes de acessar o parâmetro &lt;code&gt;TipoDocumento&lt;/code&gt;, foi necessário verificar o estado da propriedade &lt;code&gt;HasTipoDocumento&lt;/code&gt;. Se tivéssemos acessado &lt;code&gt;TipoDocumento&lt;/code&gt; diretamente, o valor retornado seria zero. No caso de &lt;code&gt;CnpjParticipante&lt;/code&gt;, podemos recuperar o valor diretamente, mesmo que seja opcional. Fazer isso não causará erro, o retorno será apenas uma string vazia. Se você precisar diferenciar entre strings vazias e valores nulos (quando o usuário não fornecer esse dado), deverá usar a propriedade &lt;code&gt;HasCnpjParticipante&lt;/code&gt;, da mesma forma como fizemos com &lt;code&gt;TipoDocumento&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Seguindo com a análise da sintaxe do arquivo .proto, temos a definição do objeto &lt;code&gt;ListDocumentoResponse&lt;/code&gt;. Nesse objeto, há uma propriedade do tipo &lt;code&gt;Documento&lt;/code&gt;, que é um objeto personalizado. No Protobuf, podemos encadear objetos livremente, e &lt;code&gt;Documento&lt;/code&gt; possui uma propriedade do tipo &lt;code&gt;Produto&lt;/code&gt; como exemplo. O termo &lt;code&gt;repeated&lt;/code&gt; que precede o tipo &lt;code&gt;Produto&lt;/code&gt; indica que essa propriedade é, na verdade, uma lista de produtos. Você pode consultar os tipos padrões e termos reservados da IDL do Protobuf &lt;a href="https://protobuf.dev/programming-guides/proto3/#scalar" rel="noopener noreferrer"&gt;aqui&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Um ponto importante a se observar quando estiver criando seus objetos. Caso sua entidade possua uma propriedade &lt;code&gt;repeat&lt;/code&gt; que pode receber uma lista muito grande dados, convêm não inclui-la no retorno de sua entidade, ao invés disso, crie uma outra função que retorne essa lista e permita que seu cliente chame simultaneamente as rotas da entidade pai e de sua lista de propriedades, dessa forma o desempenho na operação dos serviços do gRPC será muito superior.&lt;/p&gt;

&lt;p&gt;Também é possível criar enumeradores no Protobuf e passar parâmetros que aceitam valores nulos, o que elimina a necessidade do termo &lt;code&gt;optional&lt;/code&gt;. Se quiser saber mais sobre isso, você pode consultar a &lt;a href="https://protobuf.dev/reference/protobuf/google.protobuf/" rel="noopener noreferrer"&gt;documentação&lt;/a&gt;. Um conselho: se usar propriedades complexas que podem transmitir valores nulos, não use o termo &lt;code&gt;optional&lt;/code&gt;, já que não faz sentido declarar &lt;code&gt;optional&lt;/code&gt; em propriedades com tipos &lt;em&gt;nullables&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Criando serviços gRPC
&lt;/h2&gt;

&lt;p&gt;Finalmente chegamos à parte mais esperada: colocar a mão na massa! Para iniciar um projeto de servidor gRPC em C#, você pode usar o seguinte comando: &lt;code&gt;dotnet new grpc -o NomeDoProjeto&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;O resultado será um &lt;code&gt;Program&lt;/code&gt; semelhante ao seguinte:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;GrpcDocumento.Services&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;WebApplication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Add services to the container.&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddGrpc&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Configure the HTTP request pipeline.&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MapGrpcService&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;GreeterService&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A função &lt;code&gt;MapGrpcService&lt;/code&gt; inclui os arquivos de Services que você criar, fornecendo os endpoints definidos nos arquivos .proto. Para começar, basta criar seus próprios arquivos .proto e compilar o projeto. O .NET gerará as classes e tipos necessários para que seu serviço herde a classe base gerada pela compilação do arquivo .proto. Um exemplo disso pode ser visto no template, onde o serviço &lt;code&gt;GreeterService&lt;/code&gt; herda as implementações de &lt;code&gt;Greeter.GreeterBase&lt;/code&gt; e implementa os métodos definidos para o RPC.&lt;/p&gt;

&lt;p&gt;Com o conteúdo que vimos até agora, você já deve ser capaz de criar APIs gRPC simples. Então, vou pular para algo mais avançado e divertido: a criação de métodos que recebem e enviam &lt;em&gt;streams&lt;/em&gt; de dados. Se você precisar de um passo a passo mais detalhado para a criação de servidores gRPC, pode acessar o tutorial: &lt;a href="https://learn.microsoft.com/pt-br/aspnet/core/tutorials/grpc/grpc-start?view=aspnetcore-8.0&amp;amp;tabs=visual-studio" rel="noopener noreferrer"&gt;Criar um cliente e um servidor gRPC no ASP.NET Core&lt;/a&gt; disponibilizado pela Microsoft.&lt;/p&gt;

&lt;p&gt;Vamos supor que você precise criar uma função que receba e envie um &lt;em&gt;stream&lt;/em&gt; de dados. Um exemplo de implementação seria o seguinte:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;List&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;IAsyncStreamReader&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ListDocumentoRequest&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;requestStream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;IServerStreamWriter&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ListDocumentoResponse&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;responseStream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;ServerCallContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;requestStream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MoveNext&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;filter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;MapToFilter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;requestStream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Current&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;documentoList&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_documentoService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetDocumentoList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;documento&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;documentoList&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;responseStream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;documento&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Quando o arquivo .proto define a entrada de dados como &lt;em&gt;stream&lt;/em&gt;, o tipo recebido na função será &lt;code&gt;IAsyncStreamReader&amp;lt;T&amp;gt;&lt;/code&gt;, onde &lt;code&gt;T&lt;/code&gt; é o tipo de dado de entrada. Se o retorno da função for definido como stream, o tipo retornado será &lt;code&gt;IServerStreamWriter&amp;lt;T&amp;gt;&lt;/code&gt;. No &lt;code&gt;requestStream&lt;/code&gt;, você pode usar a função &lt;code&gt;MoveNext&lt;/code&gt; para aguardar o próximo pacote de dados enviado pelo cliente ou processar o pacote já recebido. No &lt;code&gt;responseStream&lt;/code&gt;, você pode usar a função &lt;code&gt;WriteAsync&lt;/code&gt; para enviar pacotes de resposta ao cliente.&lt;/p&gt;

&lt;p&gt;Se você está lidando com &lt;em&gt;streams&lt;/em&gt;, provavelmente trabalhará com grandes volumes de dados. Nesse caso, é interessante realizar consultas paginadas no banco de dados, para otimizar a eficiência e reduzir o volume de dados em trânsito. Confira abaixo um exemplo de implementação para a função &lt;code&gt;GetDocumentoList&lt;/code&gt; usada no exemplo anterior:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;IAsyncEnumerable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;DocumentoResponse&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetDocumentoList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DocumentoFilter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;documentoQuery&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_repository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetDocumentoQueryByFilter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;AsNoTracking&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;skip&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;documento&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;documentoQuery&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Skip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;skip&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;Take&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;++;&lt;/span&gt;
      &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;MapToResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;documento&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;skip&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="m"&gt;1000&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="m"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O código acima realiza consultas paginadas de 1000 em 1000 registros e processa os dados sob demanda, usando &lt;code&gt;IAsyncEnumerable&lt;/code&gt; e &lt;code&gt;yield return&lt;/code&gt; até que todos os dados compatíveis filtrados sejam retornados.&lt;/p&gt;

&lt;p&gt;Um destaque importante ao criar servidores gRPC que retornam &lt;em&gt;streams&lt;/em&gt; de dados é que os dados enviados para o &lt;em&gt;client&lt;/em&gt; são armazenados em um buffer. Como esse buffer não é infinito, se você enviar dados mais rápido do que o &lt;em&gt;client&lt;/em&gt; pode consumir, poderão ocorrer erros de estouro de buffer. Você pode ignorar esse problema e deixar que o &lt;em&gt;client&lt;/em&gt; lide com o processamento, ou pode ser uma pessoa legal e implementar técnicas que evitem isso, como aguardar um sinal do &lt;em&gt;client&lt;/em&gt; para enviar dados paginados sob demanda, de acordo com sua capacidade de processamento.&lt;/p&gt;

&lt;h3&gt;
  
  
  Consumindo uma API gRPC
&lt;/h3&gt;

&lt;p&gt;Agora, suponha que você já tenha um projeto e deseja consumir uma API gRPC. O processo é bem simples. Primeiro, instale as seguintes bibliotecas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Grpc.Net.Client&lt;/li&gt;
&lt;li&gt;Google.Protobuf&lt;/li&gt;
&lt;li&gt;Grpc.Tools&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Em seguida, adicione o código necessário no arquivo &lt;code&gt;csproj&lt;/code&gt; para mapear os arquivos .proto desejados:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;ItemGroup&amp;gt;
  &amp;lt;Protobut Includ="Protos\documento.proto" GrpcServices="Client" /&amp;gt;
&amp;lt;/ItemGroup&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para saber mais sobre as estruturas e relacionamentos entre os &lt;em&gt;nugets&lt;/em&gt; do gRPC e sua arquitetura, consulte o &lt;a href="https://grpc.io/blog/grpc-on-dotnetcore/" rel="noopener noreferrer"&gt;blog gRPC&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Agora vamos implementar a função que cria a conexão com o servidor e chama o &lt;em&gt;endpoint&lt;/em&gt; RPC&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;CallDocumentoServiceAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IEnumerable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;analiseIdList&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;channel&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;GrpcChannel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ForAddress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"endereco_grpc"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;DocumentoServiceClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;duplexStream&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;List&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;SendRequestMessageAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;analiseIdList&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;duplexStream&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;ReceiveResponseMessageAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;duplexStream&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;SendRequestMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;IEnumerable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;analiseIdList&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;AsyncDuplexStreamingCall&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ListDocumentoRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ListDocumentoResponse&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;duplexStream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;analiseId&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;analiseIdList&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;grpcRequest&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;ListDocumentoRequest&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;AnaliseId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;analiseId&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;duplexStream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RequestStream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;grpcRequest&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;duplexStream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RequestStream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CompleteAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;ReceiveResponseMessageAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;AsyncDuplexStreamingCall&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ListDocumentoRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ListDocumentoResponse&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;duplexStream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;duplexStream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseStream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Move&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// TODO: Sua implementação&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A função acima cria um canal gRPC com o endereço do servidor especificado e usa o tipo &lt;code&gt;DocumentoServiceClient&lt;/code&gt; gerado a partir da compilação do arquivo .proto para definir o serviço que será chamado. Em seguida, chamamos a função RPC &lt;code&gt;List&lt;/code&gt;, que recebe e envia um &lt;em&gt;stream&lt;/em&gt; de dados. O retorno da função é um &lt;em&gt;duplexStream&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Em seguida, na função &lt;code&gt;SendRequestMessage&lt;/code&gt;, fazemos o &lt;em&gt;stream&lt;/em&gt; das requisições, escrevendo cada solicitação com &lt;code&gt;await duplexStream.RequestStream.WriteAsync(grpcRequest);&lt;/code&gt;. Depois de enviar todos os pacotes, necessários, é importante informar ao servidor que finalizamos as requisições, chamando a função &lt;code&gt;await duplexStream.RequestStream.CompleteAsync();&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Por fim, a função &lt;code&gt;ReceiveResponseMessageAsync&lt;/code&gt; lida com o &lt;em&gt;stream&lt;/em&gt; de retorno do servidor, percorrendo cada um dos retornos com &lt;code&gt;duplexStream.ResponseStream.MoveNext()&lt;/code&gt; para processar os objetos retornados.&lt;/p&gt;

&lt;p&gt;No exemplo fornecido, estamos enviando todas as requisições e, em seguida, recebendo todos os retornos. No entanto, a conexão gRPC é bidirecional, permitindo enviar e receber dados simultaneamente. Isso significa que poderíamos colocar cada função em uma thread separada, otimizando ainda mais o desempenho do envio e recebimento de dados entre cliente e servidor.&lt;/p&gt;

&lt;p&gt;Caso você queira construir um servidor gRPC mas não queira criar um cliente apenas para testes, é possível usar o postman para consumir APIs gRPC, facilitando o teste das suas funções.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusão e referências adicionais
&lt;/h2&gt;

&lt;p&gt;O gRPC é uma ferramenta incrível para trafegar grandes volumes de dados, e há muitos cenários onde ele pode ser aplicado. Tenho certeza de que você poderá tirar grande proveito desse conhecimento.&lt;/p&gt;

&lt;p&gt;Abaixo estão alguns links adicionais que você pode gostar:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blog.lsantos.dev/guia-grpc-1/" rel="noopener noreferrer"&gt;https://blog.lsantos.dev/guia-grpc-1/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.hipsters.tech/http2-magia-com-o-novo-protocolo/" rel="noopener noreferrer"&gt;https://www.hipsters.tech/http2-magia-com-o-novo-protocolo/&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Sua lógica, sua história: O que seu código diz sobre você</title>
      <dc:creator>Mauricio Redmerski André</dc:creator>
      <pubDate>Mon, 08 Jan 2024 13:42:44 +0000</pubDate>
      <link>https://dev.to/becomex/sua-logica-sua-historia-o-que-seu-codigo-diz-sobre-voce-lld</link>
      <guid>https://dev.to/becomex/sua-logica-sua-historia-o-que-seu-codigo-diz-sobre-voce-lld</guid>
      <description>&lt;p&gt;Olá, pessoal! Espero encontrar todos bem. Hoje você aprenderá que tipo de programador você é, qual é a história que os códigos que você escreve contam sobre você, e em qual gênero literário você seria encaixado se estivesse escrevendo um livro.&lt;/p&gt;

&lt;p&gt;Escrever códigos de computadores é como escrever um livro, algumas estórias nos prendem, nos fazem querer saber mais sobre aquilo que está sendo contato, outras estórias nos repelem, e o único motivo para seguirmos lendo é a obrigação de saber o que acontece no final do livro, digo, final do código. Assim como escritores famosos, nós programadores temos cada um o seu próprio estilo, os seus próprios vícios, e marcamos nossas obras com nossa impressão digital ainda que não percebamos, e ainda que sigamos algum &lt;em&gt;style guide&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;As impressões digitais que deixamos para trás ao escrever um código de computador contam muito sobre nós mesmos, e mais ainda, a depender do nosso estilo, diria que nos permitem ser encaixados como produtores literários de livros que vão desde gêneros de romance, até gêneros de terror....&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9ovyp4pvv3zc9nu9r7el.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9ovyp4pvv3zc9nu9r7el.jpg" alt="Famosa imagem de mulher gritando ao chuveiro do filme de hitchcock" width="650" height="390"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Há algum tempo, eu tive contato com um vídeo sobre React e ficção (link nas referências), no qual a palestrante traça um paralelo entre a escrita criativa de estórias de ficção, e a escrita de códigos de computadores. Inspirado por esse conteúdo, resolvi escrever esse artigo, e nele trato de forma ilusória as minhas próprias percepções sobre os códigos que leio, comparando-os com os sentimentos que se buscam despertar os diferentes gêneros literários.&lt;/p&gt;

&lt;p&gt;**O autor adverte, qualquer semelhança com eventos reais, pessoas vivas ou mortas é mera coincidência 😁&lt;/p&gt;

&lt;p&gt;Feito o preâmbulo, você está ansioso para saber o que o seu código conta sobre você? E qual é o gênero literário que você seria encaixado se o seu código fosse um livro?&lt;/p&gt;

&lt;h2&gt;
  
  
  Os gêneros literários dos programadores
&lt;/h2&gt;

&lt;p&gt;Comecemos por definir alguns gêneros e algumas características nos códigos normalmente atribuíveis àqueles.&lt;/p&gt;

&lt;h3&gt;
  
  
  Terror
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzjw2c2ncauv4ywwn3fj0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzjw2c2ncauv4ywwn3fj0.png" alt="Freddy krueger com a mão em frente ao rosto levemente espantado" width="406" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Todos nós em algum momento da vida já tivemos que lidar com algum código que nos assustou quando estávamos lendo, e que nos rendeu alguns pesadelos a noite. De fato, existem algumas coisas que são o terror dos programadores, confere só essa pequena lista e me diga se isso não te dá um frio na espinha:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Arquivos com o número de linhas intermináveis;&lt;/li&gt;
&lt;li&gt;Linhas de código que poderiam dar a volta no planeta Terra;&lt;/li&gt;
&lt;li&gt;O mesmo nome de variável sendo usada para várias coisas diferentes;&lt;/li&gt;
&lt;li&gt;Todos os arquivos do projeto na pasta raiz do repositório;&lt;/li&gt;
&lt;li&gt;Funções que passam como parâmetro a chamada de outras funções, que passam como parâmetros a chamada de outras funções, que passam como parâmetro a chamada de outras funções, que passam como parâmetro a chamada de outras funções.... Só para deixar claro, essa crítica não se aplica em linguagens funcionais 😁.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;E por fim, e mais assustador, alguns programadores adoram esquartejar suas variáveis, muitas vezes, tudo que sobra para trás para contar história é um X marcando o local onde o ataque aconteceu.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;lst&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SOCORRO&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Suspense
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.gifer.com%2FMVV3.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.gifer.com%2FMVV3.gif" width="500" height="318"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Alguns códigos, quando precisamos debugá-los, nos dão a mesma experiência de ler um bom livro de suspense.&lt;/p&gt;

&lt;p&gt;Os códigos que estou classificando aqui como suspense são aqueles que todas as vezes que executamos, não sabemos o que esperar, às vezes funciona, às vezes gera um erro, às vezes retorna um resultado, às vezes outro.&lt;/p&gt;

&lt;p&gt;Isso costuma acontecer quando uma função faz várias coisas e possui vários efeitos colaterais, além de não deixar claro o que a mesma pretendia fazer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;funcao1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;objeto&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;o dia está ensolarado&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bora curtir uma praia&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;o vento está para o norte&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;objeto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;propriedade&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;está chovendo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;O Dev pira&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Ficção
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fochihzto3v9pkisvwhm8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fochihzto3v9pkisvwhm8.png" alt="Astronauta voando solto no espaço sideral" width="800" height="671"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ficção definitivamente é um gênero muito popular, pelo menos quando se trata de livros, quem nunca viu uma obra de Isaac Asimov? Quando falamos de algoritmos de computadores, esse gênero não é tão popular assim, é raro, mas acontece com frequência 😁.&lt;/p&gt;

&lt;p&gt;Obras de ficção costumam brincar com a realidade, e desafiam o nosso conhecimento ou extrapolam teorias, nos algoritmos de computadores isso costuma ser visto quando o autor escreve uma função cujo objetivo do que se busca e do que se faz só pode ser ficcional.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;somarNumeros&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;int&lt;/span&gt; &lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;int&lt;/span&gt; &lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;left&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Romance
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi9hl9kcmfx0tif3xvyq3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi9hl9kcmfx0tif3xvyq3.png" alt="Filme a dama e o vagabundo, com os cães comendo um mesmo pedaço de espaguete" width="728" height="385"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;O amor é lindo, e mais lindo que o amor é um código escrito com paixão. Programadores experientes conseguem ver através do código e dizer com quanto carinho o código foi escrito pelo autor.&lt;/p&gt;

&lt;p&gt;Poucas coisas são tão satisfatórias quanto trabalhar com um código que foi escrito com esmero, é possível sentir quando o programador se esforçou em tornar o seu trabalho entendível e lapidado. Ainda que não seja o melhor código possível, e não se trata disso! Um programador que escreve romances toma o cuidado de deixar as coisas onde se espera que elas estejam, e conduzem o leitor de seus códigos em uma valsa de funções e variáveis imitando o mais belo dos sonetos.&lt;/p&gt;

&lt;p&gt;Escritores deste gênero tomam o cuidado de indentar seus códigos com um padrão bem estabelecido, ainda que o leitor prefira outras formatações, é notável que o autor se esforçou para manter tudo com a mesma estética, e não jogou simplesmente os elementos na tela como quem bate com a cabeça no teclado.&lt;/p&gt;

&lt;h2&gt;
  
  
  As revelações que os códigos fazem sobre seus autores
&lt;/h2&gt;

&lt;p&gt;Tendo visto alguns gêneros literários usados para falar de características gerais dos desenvolvedores, daremos sequência observando algumas características mais pontuais, itens que os códigos revelam sobre os autores.&lt;/p&gt;

&lt;h3&gt;
  
  
  Programador Ultrawide Screen
&lt;/h3&gt;

&lt;p&gt;Alguns programadores usam todo o espaço disponível de seus monitores para escrever seus códigos, pode ser muito fácil descobrir o tamanho do monitor de alguns desenvolvedores, basta contar quantas vezes você precisa rolar o código horizontalmente para descobrir se o desenvolvedor que o fez possui um monitor Ultrawide Screen.&lt;/p&gt;

&lt;h3&gt;
  
  
  Programador Shakespeariano
&lt;/h3&gt;

&lt;p&gt;Esses programadores normalmente escrevem códigos que se encaixam no gênero de romance, suas obras são em geral muito belas, o único problema é que poucas pessoas são capazes de entendê-las.&lt;/p&gt;

&lt;h3&gt;
  
  
  Programadores que amam e odeiam espaço em branco
&lt;/h3&gt;

&lt;p&gt;Alguns programadores amam usar a tecla de espaço, adicionam vários espaços entre seus códigos, seja verticalmente deixando um vasto espaço vazio entre funções, ou horizontalmente iniciando uma linha na metade da tela.&lt;/p&gt;

&lt;p&gt;Por outro lado, há aqueles que a detestam, não incluem espaços entre elementos de uma linha, e muito menos entre blocos de funções, tudo se torna uma grande sequência de caracteres concatenados.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;Ler e interpretar códigos compõem a maior parte do trabalho de um desenvolvedor, seja para integrar uma nova feature à um código já existente, corrigir um bug, ou refatorar algum trecho de código. Estamos sempre lendo códigos e tentando entender o que raios ele está fazendo, seja esse escrito por alguém da nossa equipe ou por nós mesmos há alguns meses. Por esse motivo, escrever de forma consistente e aplicar corretamente os padrões de desenvolvimento são tão importantes, isso nos ajuda a comunicar a intenção do código para as outras pessoas, e para nós mesmos no futuro.&lt;/p&gt;

&lt;p&gt;O objetivo deste texto foi chamar a atenção de forma divertida para alguns anti-patterns e vícios negativos que temos no desenvolvimento de código, de forma que quando estejamos escrevendo algum código, nos perguntemos: que tipo de estória eu estou contando? Quem está lendo meu código se sentirá lendo um romance ou uma estória de terror?&lt;/p&gt;

&lt;p&gt;É sempre mais agradável lidar com código claros e bem escritos, ainda que o código não seja o melhor, é possível notar quando o desenvolvedor se importava com o que estava fazendo, e queria entregar o melhor que podia naquele momento.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dicas do autor
&lt;/h2&gt;

&lt;p&gt;Quer deixar de escrever estórias de terror e começar a escrever verdadeiros romances? Que tal começar aplicando algumas estratégias de &lt;em&gt;clean code&lt;/em&gt; básicas?&lt;/p&gt;

&lt;p&gt;Preparei uma pequena lista de tópicos pensando no que vimos dentro dos gêneros literários deste artigo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Nem todos os desenvolvedores possuem um super monitor, controle o comprimento das linhas do seu código, 80 caracteres é excelente, 120 é aceitável;&lt;/li&gt;
&lt;li&gt;Se o arquivo está muito grande, separe o código em arquivos menores de acordo com as responsabilidades do código;&lt;/li&gt;
&lt;li&gt;Separou o código em vários arquivos? Ótimo, agora os organize em pastas no seu projeto, não deixe tudo na pasta raiz;&lt;/li&gt;
&lt;li&gt;Use nomes reveladores nas variáveis e funções, abreviaturas e usar apenas uma letra como variável dificulta muito a manutenção do código;&lt;/li&gt;
&lt;li&gt;Certifique-se de que a função escrita faz o que o nome dela expressa;&lt;/li&gt;
&lt;li&gt;Use o espaço vertical e horizontal, mas também não exagere, os elementos não precisam estar unidos, mas também não precisam estar em quarentena um longe do outro;&lt;/li&gt;
&lt;li&gt;Siga apenas uma indentação, mesmo que não seja a melhor de todas ela demonstra consistência, poucas coisas mostram mais desleixo do que cada parte de um código escrito e indentado de formas completamente diferentes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Lembre-se: escritores de livros não publicam a primeira versão de seus manuscritos, eles leem e releem suas obras e as lapidam, do mesmo jeito, você não deveria publicar a primeira versão do seu código, uma revisão ainda que rápida não fará mal a ninguém.&lt;/p&gt;

&lt;p&gt;Agora, me conta: que tipo de gênero literário você tem escrito atualmente?&lt;/p&gt;

&lt;h2&gt;
  
  
  Referências
&lt;/h2&gt;

&lt;p&gt;React e ficção: &lt;a href="https://www.youtube.com/watch?v=kqh4lz2Lkzs" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=kqh4lz2Lkzs&lt;/a&gt;&lt;br&gt;
Livro: Código limpo: habilidades práticas do Agile software&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Executando funções personalizadas no banco de dados usando SqlExpression no .Net</title>
      <dc:creator>Mauricio Redmerski André</dc:creator>
      <pubDate>Sat, 06 May 2023 20:26:24 +0000</pubDate>
      <link>https://dev.to/becomex/executando-funcoes-personalizadas-no-banco-de-dados-usando-sqlexpression-no-net-28i</link>
      <guid>https://dev.to/becomex/executando-funcoes-personalizadas-no-banco-de-dados-usando-sqlexpression-no-net-28i</guid>
      <description>&lt;p&gt;Olá, pessoal! Espero encontrar todos bem. Hoje teremos um material "mão na massa", demonstrando como fazer o EF Core (Entity Framework Core) ser capaz de traduzir funções personalizadas no banco de dados em expressões construídas com Linq (Consulta Integrada à Linguagem), que normalmente, não seria possível traduzi-las.&lt;/p&gt;

&lt;p&gt;Se você trabalha com a linguagem de programação C#, certamente já escreveu alguma &lt;em&gt;query&lt;/em&gt; com Linq que executa perfeitamente quando a lista de dados da operação envolvida já está carregada em memória, mas teve uma triste surpresa ao tentar aplicar o mesmo código acessando dados que estavam no banco, recebendo algum erro similar a este:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; The LINQ expression could not be translated
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Isso ocorre porque há um limite acerca do que o EF Core é capaz de traduzir para linguagem nativa do banco de dados configurado em seu projeto, restringindo assim as possibilidades de uso do que pode ser feito diretamente no banco, em ralação ao que pode ser feito quando os dados já estão em memória. Mas há uma luz no fim do túnel, e não se preocupe, não é um trem vindo em sua direção... Podemos usar o recurso &lt;em&gt;SqlExpression&lt;/em&gt; para ensinar o EF Core a traduzir comandos que ele nativamente não consegue, sendo essas operações nativas do seu banco de dados, ou funções criadas por você dentro do banco de dados.&lt;/p&gt;

&lt;p&gt;Antes de começarmos efetivamente, vamos dar uma olhada nas versões de pacotes e programas que estou usando, sabemos que o modo como os recursos são implementados podem variar de acordo com suas versões, então para não haver mal-entendidos, estou usando o .Net 5 e o banco de dados SQL Server 2016, um pouco datado, eu sei.&lt;/p&gt;

&lt;p&gt;Vamos começar com um problema simples. Imagine que você precise realizar uma consulta em uma massa de dados de &lt;em&gt;Players&lt;/em&gt;, e retornar às seguintes propriedades: &lt;em&gt;Name&lt;/em&gt;, &lt;em&gt;Score&lt;/em&gt;, e a posição do player no ranking, que claro, é calculado a partir do Score. Para atender a essa demanda, um simples código como o seguinte pode ser usado&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;playerList&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Player&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Player&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Mauricio"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Score&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Player&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"André"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Score&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;6&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Player&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Redmerski"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Score&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;8&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;playerDtoList&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;playerList&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;OrderByDescending&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;player&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;player&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PlayerDto&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Score&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Position&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToList&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esse código funciona perfeitamente porque os dados que esse algoritmo manipula estão carregados em memória, se você trocar a variável playerList de modo a apontar para uma base de dados, usando &lt;code&gt;dbContext.PlayersDbSet&lt;/code&gt; por exemplo, descobrirá que isso não pode ser traduzido para um comando SQL. O parâmetro &lt;em&gt;index&lt;/em&gt; contido no &lt;em&gt;Select&lt;/em&gt; representa a posição do item percorrido dentro da lista carregada em memória, logo se os dados não estão em memória, essa informação não existe. Poderíamos esperar que essa posição fosse substituída pela função do banco de dados que determina a linha da consulta, chamado de &lt;em&gt;ROW_NUMBE&lt;/em&gt; no SQL Server, mas o EF Core não tem uma forma simples de executar essa operação para retornar o número da linha do registro em uma consulta ao banco de dados.&lt;/p&gt;

&lt;p&gt;PS: Eu sei que você está com vontade de comentar que esse código não prevê a possibilidade de dois ou mais jogadores estarem empatados, mas quero manter as coisas simples, então segura essa vontade 😁.&lt;/p&gt;

&lt;p&gt;Certo, então como podemos tornar essa operação traduzível ao banco de dados? Muito simples meu caro leitor, basta seguirmos os passos abaixo. Ah, os nomes e estruturas que mostro abaixo são uma representação de como eu acredito que essas funções devem ser organizadas, fique à vontade para alterá-las.&lt;/p&gt;

&lt;p&gt;Começamos criando um diretório dentro do seu projeto responsável por lidar com a infraestrutura, especificamente o banco de dados, chamo essa pasta de &lt;em&gt;Functions&lt;/em&gt;, dentro dessa pasta crio um arquivo chamado &lt;em&gt;EfCoreCustomFunctions&lt;/em&gt;, dentro desse crio uma função chamada &lt;em&gt;RowNumber&lt;/em&gt; que recebe três parâmetros, um parâmetro do tipo &lt;em&gt;long&lt;/em&gt; que representará a coluna do banco de dados também do mesmo tipo que será usada para particionar a enumeração, um segundo parâmetro do tipo &lt;em&gt;long&lt;/em&gt; que representará a coluna pela qual a ordenação deve ser aplicada para a enumeração, e um parâmetro &lt;em&gt;booleano&lt;/em&gt; que indica a direção de ordenação, quando verdadeiro a ordem é ascendente. Observe que o conteúdo dessa função não é importante, então podemos simplesmente lançar uma exceção.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;MyProject.EntityFrameworkCore&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EfCoreCustomFunctions&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="nf"&gt;RowNumber&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;partition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;ordering&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="k"&gt;ascending&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;NotSupportedException&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Em seguida crio um arquivo na mesma pasta chamado &lt;em&gt;RowNumberFunction&lt;/em&gt;, é dentro desse arquivo que a função realmente será criada. Nesse arquivo crio uma função de extensão para a classe &lt;em&gt;ModelBuilder&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;MyProject.EntityFrameworkCore&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RowNumberFunction&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;ModelBuilder&lt;/span&gt; &lt;span class="nf"&gt;AddRowNumberFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="n"&gt;ModelBuilder&lt;/span&gt; &lt;span class="n"&gt;modelBuilder&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;modelBuilder&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A primeira coisa a ser feita é recuperar o tipo da classe que criamos para manter as assinaturas dos nossos métodos, e usar a função &lt;em&gt;GetMethod&lt;/em&gt; para capturar a assinatura do método específico desejado. Eu gosto de especificar explicitamente os tipos dos parâmetros da função em questão, passando-os como segundo parâmetro da função &lt;em&gt;GetMethod&lt;/em&gt;, mas se houver apenas uma função com o nome especificado, essa etapa é opcional.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;method&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EfCoreCustomFunctions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetMethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;nameof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EfCoreCustomFunctions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RowNumber&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="p"&gt;?),&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Em seguida vem o passo mais importante: instruir o EF Core de fato a como traduzir esse comando, e podemos fazer isso de algumas formas&lt;/p&gt;

&lt;p&gt;Depois de usar o &lt;em&gt;modelMuilder&lt;/em&gt; para chamar a função &lt;em&gt;HasDbFunction&lt;/em&gt; passando como parâmetro a variável &lt;em&gt;method&lt;/em&gt; criada na etapa anterior, podemos usar a função &lt;em&gt;HasName&lt;/em&gt; e passar o nome de uma função personalizada que nós criamos diretamente no banco.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;modelBuilder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;HasDbFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;HasName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MinhaFuncaoJaCriadaNaBase"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Eu particularmente não gosto de criar funções diretamente no banco de dados, entendo como a melhor opção usarmos o método &lt;em&gt;HasTranslation&lt;/em&gt; após a função &lt;em&gt;HasDbFunction&lt;/em&gt;, esse método nos permite instruir o EF Core a como a operação precisa ser criada, sem que a função exista previamente na base, assim mantemos todas as regras de operação dentro do nosso programa. É claro que esse é um posicionamento particular, a função &lt;em&gt;HasName&lt;/em&gt; existe para ser usada, então fique à vontade para fazer uso da mesma caso ela atenda ao seu cenário.&lt;/p&gt;

&lt;p&gt;A função &lt;em&gt;HasTranslation&lt;/em&gt; recebe uma &lt;em&gt;function&lt;/em&gt; que contém uma lista de &lt;em&gt;SqlExpression&lt;/em&gt;, essa lista é uma representação dos parâmetros que foram enviados para a função, e retorna um &lt;em&gt;SqlExpression&lt;/em&gt; que será a função a ser executada. Sim, os tipos de entrada e saídas são iguais, isso porque o parâmetro da sua função pode ser o resultado de uma outra função traduzida para o banco.&lt;/p&gt;

&lt;p&gt;A operação &lt;em&gt;RowNumber&lt;/em&gt; em que estamos trabalhando possui a classe &lt;em&gt;RowNumberExpression&lt;/em&gt; que facilita sua implementação e é herdeira de &lt;em&gt;SqlExpression&lt;/em&gt;. Essa classe recebe como parâmetro uma lista opcional com os campos da base a serem usados como partição de agrupamento para a enumeração das linhas, uma lista obrigatória da classe &lt;em&gt;OrderingExpression&lt;/em&gt; que contém o nome da coluna a ser usada na ordenação e a direção de ordenação, e o tipo de retorno esperado.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;modelBuilder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;HasDbFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;HasTranslation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;RowNumberExpression&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;OrderingExpression&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;LongTypeMapping&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"long"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DbType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Int64&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Os parâmetros da função &lt;em&gt;RowNumber&lt;/em&gt; que criamos em nossa classe &lt;em&gt;EfCoreCustomFunctions&lt;/em&gt; são um pouco diferentes do que é esperado, então vamos manipulá-los um pouco. Primeiro vamos verificar se o primeiro parâmetro que enviamos é do tipo &lt;em&gt;SqlConstantExpression&lt;/em&gt;, qualquer constante enviada geraria o mesmo resultado, então eu prefiro testar essa condição, e caso ela seja verdadeira, passar o valor &lt;em&gt;null&lt;/em&gt; como parâmetro.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;modelBuilder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;HasDbFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;HasTranslation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;RowNumberExpression&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;First&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="n"&gt;SqlConstantExpression&lt;/span&gt;
                &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;
                &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Take&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;ToList&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;OrderingExpression&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;LongTypeMapping&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"long"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DbType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Int64&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Em seguida vamos criar um item na lista passada como segundo parâmetro, esse item vai ter os outros dois campos que recebemos em nossa função de ordenação personalizada. Observe que dada a natureza do tipo do objeto &lt;em&gt;args&lt;/em&gt;, precisamos primeiro converter o terceiro parâmetro recebido para &lt;em&gt;SqlConstantExpression&lt;/em&gt; para só então conseguir convertê-lo para &lt;em&gt;booleano&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;modelBuilder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;HasDbFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;HasTranslation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;RowNumberExpression&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;First&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="n"&gt;SqlConstantExpression&lt;/span&gt;
                &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;
                &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Take&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;ToList&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;OrderingExpression&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;OrderingExpression&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Skip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;First&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                    &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)((&lt;/span&gt;&lt;span class="n"&gt;SqlConstantExpression&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Skip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;First&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;LongTypeMapping&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"long"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DbType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Int64&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O código final dessa classe deve se parecer com o seguinte:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Collections.Generic&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Linq&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.EntityFrameworkCore&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.EntityFrameworkCore.Query.SqlExpressions&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.EntityFrameworkCore.Storage&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;MyProject.EntityFrameworkCore&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RowNumberFunction&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;ModelBuilder&lt;/span&gt; &lt;span class="nf"&gt;AddRowNumberFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="n"&gt;ModelBuilder&lt;/span&gt; &lt;span class="n"&gt;modelBuilder&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;method&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EfCoreCustomFunctions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetMethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="k"&gt;nameof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EfCoreCustomFunctions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RowNumber&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                    &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="p"&gt;?),&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

            &lt;span class="n"&gt;modelBuilder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;HasDbFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;HasTranslation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
                    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;RowNumberExpression&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                        &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;First&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="n"&gt;SqlConstantExpression&lt;/span&gt;
                            &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;
                            &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Take&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;ToList&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;OrderingExpression&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;
                        &lt;span class="p"&gt;{&lt;/span&gt;
                            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;OrderingExpression&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                                &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Skip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;First&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                                &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)((&lt;/span&gt;&lt;span class="n"&gt;SqlConstantExpression&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Skip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;First&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                        &lt;span class="p"&gt;},&lt;/span&gt;
                        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;LongTypeMapping&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"long"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DbType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Int64&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                    &lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;modelBuilder&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora tudo que temos que fazer é chamar a construção desse método dentro do &lt;em&gt;ModelBuilder&lt;/em&gt;, para que quando tentarmos usá-lo, ele saiba exatamente o que fazer. Para isso, vamos criar uma classe chamada &lt;em&gt;ModelFunctionsExtensions&lt;/em&gt; dentro da pasta &lt;em&gt;Functions&lt;/em&gt;, vamos usar esse arquivo para chamar todas as funções customizadas que criaremos no futuro.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.EntityFrameworkCore&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;MyProject.EntityFrameworkCore&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ModelFunctionsExtensions&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;ModelBuilder&lt;/span&gt; &lt;span class="nf"&gt;AddCustomFunctions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="n"&gt;ModelBuilder&lt;/span&gt; &lt;span class="n"&gt;modelBuilder&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;modelBuilder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddRowNumberFunction&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;modelBuilder&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora no local onde você cria o seu contexto, tudo que você tem a fazer é incluir a seguinte linha &lt;code&gt;builder.AddCustomFunctions();&lt;/code&gt; e todas as configurações estarão prontas. É claro que a variável &lt;em&gt;builder&lt;/em&gt; é uma instância de &lt;em&gt;ModelBuilder&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Agora vamos ver como podemos alterar o nosso código de exemplo para usar a função que acabamos de criar. Primeiro vamos acessar os dados diretamente do contexto, e na atribuição da propriedade &lt;em&gt;Position&lt;/em&gt;, vamos chamar nossa função &lt;em&gt;RowNumber&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;playerDtoList&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;playerList&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;OrderByDescending&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;player&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;player&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PlayerDto&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Score&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Position&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;EfCoreCustomFunctions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RowNumber&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToList&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pronto! Esse código será capaz de ser traduzido pelo EF Core, e a posição do player será calculada diretamente no banco de dados. Veja um exemplo de como essa &lt;em&gt;query&lt;/em&gt; se parecerá quando for executada no banco de dados.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Score&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ROW_NUMBER&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;OVER&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;Score&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="k"&gt;Position&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;Playes&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;Score&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Que tal olharmos rapidamente mais um exemplo de função, mas dessa vez um exemplo que use a classe &lt;em&gt;SqlFunctionExpression&lt;/em&gt;? Essa classe recebe como primeiro parâmetro o nome da função a ser executado, os argumentos a serem transmitidos, um indicador se o retorno pode ser nulo, e uma lista com o mesmo número de argumentos passados que representa a possibilidade de os parâmetros enviados serem nulos, um parâmetro do tipo &lt;em&gt;System.Type&lt;/em&gt; e outro &lt;em&gt;RelationalTypeMapping&lt;/em&gt; respectivamente, ambos indicando o tipo de retorno da função.&lt;/p&gt;

&lt;p&gt;Vamos criar um método que chama a função &lt;em&gt;Replicate&lt;/em&gt; do banco de dados, começamos incluindo a função &lt;em&gt;Replicate&lt;/em&gt; à nossa classe &lt;em&gt;EfCoreCustomFunctions&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;MyProject.EntityFrameworkCore&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EfCoreCustomFunctions&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="nf"&gt;RowNumber&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;partition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;ordering&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="k"&gt;ascending&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;NotSupportedException&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;Replicate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;replicate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;NotSupportedException&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora criamos o nosso arquivo &lt;em&gt;ReplicateFunction&lt;/em&gt; e criamos um conteúdo muito semelhante ao exemplo anterior, mas agora usando &lt;em&gt;SqlFunctionExpression&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Collections.Generic&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Linq&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.EntityFrameworkCore&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.EntityFrameworkCore.Query.SqlExpressions&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.EntityFrameworkCore.Storage&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;MyProject.EntityFrameworkCore&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ReplicateFunction&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;ModelBuilder&lt;/span&gt; &lt;span class="nf"&gt;AddReplicateFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="n"&gt;ModelBuilder&lt;/span&gt; &lt;span class="n"&gt;modelBuilder&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;method&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EfCoreCustomFunctions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetMethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="k"&gt;nameof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EfCoreCustomFunctions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Replicate&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                    &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

            &lt;span class="n"&gt;modelBuilder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;HasDbFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;HasTranslation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
                    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;SqlFunctionExpression&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                        &lt;span class="s"&gt;"REPLICATE"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                        &lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;StringTypeMapping&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DbType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                    &lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;modelBuilder&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora basta incluir a linha &lt;code&gt;modelBuilder.AddReplicateFunction();&lt;/code&gt; na função &lt;em&gt;AddCustomFunctions&lt;/em&gt; do arquivo &lt;em&gt;ModelFunctionsExtensions&lt;/em&gt; e nossa função já está pronta para ser usada.&lt;/p&gt;

&lt;h2&gt;
  
  
  Nota do autor
&lt;/h2&gt;

&lt;p&gt;Conhecer recursos como esses a respeito da ferramenta com a qual trabalhamos é muito importante, e nos permite fazer coisas incríveis em nossas aplicações. Espero que esse artigo o tenha ajudado a resolver o que você precisava, ou ao menos incluído mais uma ferramenta em sua caixa de ferramentas para lidar com o complexo e maravilhoso mundo da programação.&lt;/p&gt;

&lt;p&gt;Abraço!&lt;/p&gt;

&lt;h2&gt;
  
  
  Fontes e leituras complementares
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://learn.microsoft.com/en-us/ef/core/querying/user-defined-function-mapping" rel="noopener noreferrer"&gt;https://learn.microsoft.com/en-us/ef/core/querying/user-defined-function-mapping&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.allhandsontech.com/data-professional/entityframework/entity-framework-core-advanced-mapping/" rel="noopener noreferrer"&gt;https://www.allhandsontech.com/data-professional/entityframework/entity-framework-core-advanced-mapping/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://khalidabuhakmeh.com/add-custom-database-functions-for-entity-framework-core" rel="noopener noreferrer"&gt;https://khalidabuhakmeh.com/add-custom-database-functions-for-entity-framework-core&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://stackoverflow.com/questions/56261258/mixing-ef-core-convensions-and-dbfunction-for-a-jobject-property" rel="noopener noreferrer"&gt;https://stackoverflow.com/questions/56261258/mixing-ef-core-convensions-and-dbfunction-for-a-jobject-property&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://medium.com/@pawel.gerr/entity-framework-core-custom-functions-using-hasdbfunction-191dd57e4967" rel="noopener noreferrer"&gt;https://medium.com/@pawel.gerr/entity-framework-core-custom-functions-using-hasdbfunction-191dd57e4967&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://medium.com/@pawel.gerr/entity-framework-core-custom-functions-using-imethodcalltranslator-f8209ae6f95b" rel="noopener noreferrer"&gt;https://medium.com/@pawel.gerr/entity-framework-core-custom-functions-using-imethodcalltranslator-f8209ae6f95b&lt;/a&gt;&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>programming</category>
    </item>
    <item>
      <title>Conversando com alienígenas, uma breve introdução ao Gherkin</title>
      <dc:creator>Mauricio Redmerski André</dc:creator>
      <pubDate>Thu, 16 Feb 2023 19:55:34 +0000</pubDate>
      <link>https://dev.to/becomex/conversando-com-alienigenas-uma-breve-introducao-ao-gherkin-2601</link>
      <guid>https://dev.to/becomex/conversando-com-alienigenas-uma-breve-introducao-ao-gherkin-2601</guid>
      <description>&lt;p&gt;Olá, pessoal! Espero encontrar todos bem. Hoje vocês aprenderão a se comunicar com uma espécie muito curiosa e intrigante que vive sobre a superfície do nosso pálido ponto azul - ou planeta Terra se você não for tão íntimo.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffbw06xllrarhbdauditx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffbw06xllrarhbdauditx.png" alt="Aliens" width="610" height="534"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Mas, antes de começarmos, preciso esclarecer uma coisa: se você começou a ler esse artigo esperando aprender a conversar com alienígenas de verdade, e talvez pensou que Gherkin fosse alguma máquina maluca de tradução de linguagens intergalácticas, detesto te desapontar, mas esse artigo não é bem sobre isso. Mas não desista de ler ele agora, prometo que esse material pode ser útil para você (mesmo se você realmente estiver querendo falar com aliens).&lt;/p&gt;

&lt;p&gt;Certo, então qual é a espécie intrigante a qual eu me referi no começo do artigo? E sobre o que é esse material afinal?&lt;/p&gt;

&lt;p&gt;No contexto deste artigo, quando falo em alienígenas, faço uma brincadeira com as pessoas da categoria a qual pertenço, me refiro a programadores e programadoras (devs) que em geral tem uma forma muito peculiar de interpretar o que as pessoas falam - darei exemplos e deixarei a analogia mais clara adiante. Esse artigo faz uma introdução a uma sintaxe, um modo de escrever determinado contexto, que elimina termos que possam não ser conhecidos por todos os interlocutores fazendo-o de uma forma declarativa, deste modo todos são capazes de compreender o contexto e qual é a mensagem a ser transmitida, aumentando assim a eficiência da comunicação entre os membros de um time em um ambiente de desenvolvimento de software, e claro, tornando mais fácil para nós desenvolvedores entender o que precisa ser feito. E o nome dessa estrutura mágica é Gherkin.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problemática
&lt;/h2&gt;

&lt;p&gt;Vamos fazer o seguinte experimento mental: imagine que uma nave alienígena pouse na sua frente, dela sai um homenzinho verde com clara capacidade de manter uma comunicação complexa, mas você não entende um único som que esse visitante espacial emite, e ele também não possui nenhum conhecimento prévio sobre sua língua e cultura. O que você faria para tentar compreender o que nosso visitante está dizendo e como você ensinaria a ele nossa língua para que ele pudesse nos entender?&lt;/p&gt;

&lt;p&gt;A ideia de trazer esse experimento é causar a reflexão sobre como podemos nos comunicar com pessoas que não possuem o mesmo background que nós, que possuem outras ideias, onde aquilo que é óbvio para nós não é óbvio para nossos ouvintes. Nessa analogia, o homenzinho verde são os devs, e a questão é como um analista de negócio, gerente de produto ou qualquer outro estabelece contato conosco e nos solicita o desenvolvimento de uma nova funcionalidade. É claro que os papéis de marciano e terrestre podem ser facilmente invertidos, e que essa reflexão não vale apenas para comunicações onde devs estão envolvidos, mas também com qualquer pessoa, lembre-se que não é porque você fala a mesma linguagem que alguém, que não existirão ruídos na comunicação.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mais uma historinha
&lt;/h3&gt;

&lt;p&gt;Talvez você já tenha ouvido a piada onde alguém pede para um dev ir ao mercado com a seguinte instrução "Compre uma caixa de leite, e se tiver ovos traga dois" e assim o dev compra duas caixas de leite ao invés de uma caixa de leite e dois ovos como o solicitante queria. A piada pode ser engraçada, mas não é nada divertido quando essas confusões acontecem durante o desenvolvimento de um software, e a feature implementada não faz o que o solicitante esperava.&lt;/p&gt;

&lt;p&gt;Por essa razão, o modo como uma funcionalidade deve ser descrita é muito importante, não só para o programador, mas para que todos os envolvidos no processo de construção de um software tenham o mesmo entendimento do que deve ser feito.&lt;/p&gt;

&lt;p&gt;Só para constar, acho totalmente aceitável comprar duas caixas de leite considerando a instrução fornecida.&lt;/p&gt;

&lt;h2&gt;
  
  
  Falando sobre Gherkin
&lt;/h2&gt;

&lt;p&gt;Gherkin é um dos elementos presentes no BDD (Behavior Driven Development) e basicamente consiste em escrever cenários de forma padronizadas, baseadas nas regras de negócio e usando palavras-chave para compor os passos que devem ser seguidos até uma conclusão, sendo sempre escritas na terceira pessoa.&lt;br&gt;
Apesar de descrever as regras de negócio, o uso de palavras e termos que pertencem ao negócio deve ser evitado, é ideal que qualquer pessoa consiga ler e interpretar o que deve ser feito, mesmo que não possuam conhecimento de negócio. Em igual medida, termos técnicos e exemplo de codificação devem ser omitidos, essa especificação é o ponto onde todos os envolvidos na construção do software se encontram, sendo assim não pode haver termos que só um dos lados entenda.&lt;/p&gt;

&lt;p&gt;Além do motivo supracitado para não acrescentar códigos na solicitação de uma demanda, existe outra boa razão para não fazer isso, o maior valor que um desenvolvedor entrega não é quanto código ele escreve, mas os problemas que ele resolve, somos bons em resolver problemas e gostamos disso, entregar o problema resolvido para "apenas" escrever o código elimina a maior entrega de valor que podemos dar, além de nos matar vagarosamente.&lt;/p&gt;

&lt;p&gt;Os arquivos com a estrutura Gherkin são normalmente salvos com a extensão &lt;em&gt;feature&lt;/em&gt; e possuem notações iniciadas com cerquilha # para indicar por exemplo a linguagem das palavras-chave usadas naquele arquivo, a indentação do conteúdo é estruturado com espaços e quebra de linha, deste modo o aninhamento do conteúdo e as palavras-chave são identificadas. Essas especificações são especialmente importantes se você for manter esses conteúdos escritos em arquivos, mas nada o impede de usar a caixa de texto de algum sistema para manter esse conteúdo, a fim de usar a ideia e as palavras-chave do Gherkin nas definições de suas demandas no software de gerenciamento de projetos que sua empresa já usa.&lt;/p&gt;
&lt;h3&gt;
  
  
  Palavras-chave
&lt;/h3&gt;

&lt;p&gt;A lista abaixo apresenta as palavras-chave do Gherkin com uma breve descrição sobre seu objetivo&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Feature&lt;/strong&gt;: Descreve em níveis mais altos o propósito da funcionalidade e agrupa os diferentes cenários que podem existir;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Background&lt;/strong&gt;: É o contexto, um conjunto inicial de steps que se repetem em todos os cenários da feature;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scenario&lt;/strong&gt; ou &lt;strong&gt;Example&lt;/strong&gt;: Descreve um exemplo concreto sobre a regra de negócio e é ou não seguido por steps, é possível incluir quantos steps desejar;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scenario Outline&lt;/strong&gt;: Usado para descrever um cenário que se repete alterando as entradas e saídas;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Examples&lt;/strong&gt;: Usado para construir um conjunto de exemplos de entrada e saída para usar dentro do Scenario Outline;&lt;/li&gt;
&lt;li&gt;Step &lt;strong&gt;Given&lt;/strong&gt;: Descreve a condição inicial do cenário;&lt;/li&gt;
&lt;li&gt;Step &lt;strong&gt;When&lt;/strong&gt;: Descreve um evento que normalmente causa uma mudança;&lt;/li&gt;
&lt;li&gt;Step &lt;strong&gt;Then&lt;/strong&gt;: Descreve o resultado esperado após o evento;&lt;/li&gt;
&lt;li&gt;Step &lt;strong&gt;And&lt;/strong&gt;: Pode ser usado para concatenar de forma positiva sentenças dos steps anteriores;&lt;/li&gt;
&lt;li&gt;Step &lt;strong&gt;But&lt;/strong&gt;: Pode ser usado para acrescentar uma negativa de forma subsequente a um dos steps superiores;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Casos de testes escritos com Gherkin
&lt;/h3&gt;

&lt;p&gt;Para entendermos melhor a diferença entre simplesmente escrever a funcionalidade e escrevê-la usando Gherkin, que tal observamos um exemplo simples de login de usuário escritos das duas maneiras?&lt;/p&gt;

&lt;p&gt;Simplesmente descrevendo:&lt;br&gt;
Quando eu acessar o site e ir até a página de login e preencher o login a senha e clicar no botão de iniciar sessão, uma requisição a api do site deve ser feita transmitindo os dados preenchidos, se o resultado enviado pela api for positivo, uma mensagem de login efetuado com sucesso deve ser apresentada e o site deve me redirecionar para a página inicial do site mantendo minha sessão na memória do navegador.&lt;/p&gt;

&lt;p&gt;Usando o Gherkin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;Feature&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Login de usuário&lt;/span&gt;

  &lt;span class="s"&gt;Scenario&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Login de usuário válido&lt;/span&gt;
    &lt;span class="s"&gt;Given que o usuário possua uma conta no site&lt;/span&gt;
    &lt;span class="s"&gt;And acesse a página de login&lt;/span&gt;
    &lt;span class="s"&gt;And preencha corretamente os dados de acesso&lt;/span&gt;
    &lt;span class="s"&gt;When ele acionar o botão de entrar no sistema&lt;/span&gt;
    &lt;span class="s"&gt;Then uma mensagem de sucesso deve ser apresentada&lt;/span&gt;
    &lt;span class="s"&gt;And ele deve ser direcionado logado a página inicial do site&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Como se pode observar, o modelo escrito com Gherkin é muito mais claro e omite qualquer detalhe técnico do desenvolvimento. Que tal darmos uma olhada em outro exemplo, agora usando as palavras-chave faltantes?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;Feature&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Café da tarde&lt;/span&gt;

&lt;span class="na"&gt;Background&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="s"&gt;Given que os escritores de artigos sentem fome&lt;/span&gt;

&lt;span class="na"&gt;Scenario Outline&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Comendo fatias de bolo&lt;/span&gt;
  &lt;span class="s"&gt;Given que existe &amp;lt;inicial&amp;gt; fatias de bolo&lt;/span&gt;
  &lt;span class="s"&gt;When for comido &amp;lt;comido&amp;gt; fatias de bolo&lt;/span&gt;
  &lt;span class="s"&gt;Then deve restar &amp;lt;restante&amp;gt; fatias de bolo&lt;/span&gt;

  &lt;span class="s"&gt;Examples&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;|&lt;/span&gt; &lt;span class="err"&gt;inicial&lt;/span&gt; &lt;span class="err"&gt;|&lt;/span&gt; &lt;span class="err"&gt;comido&lt;/span&gt; &lt;span class="err"&gt;|&lt;/span&gt; &lt;span class="err"&gt;restante&lt;/span&gt; &lt;span class="err"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;|    10   |    3   |     7    |&lt;/span&gt;
    &lt;span class="s"&gt;|     5   |    5   |     0    |&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Apesar dos exemplos modestos, acredito que seja possível compreender a ideia geral. Alguém poderia dizer que esse modelo adiciona mais trabalho na escrita dos cenários, ou mesmo que essa divisão parece infantil e que um texto corrido teria o mesmo efeito. Qualquer quantia de tempo acrescido na criação das descrições das atividades seria recuperada, uma vez que seria poupando tempo de manutenção e correções por conta do desentendimento quanto ao objetivo da função. Quanto a divisão parecer infantil, pense que você está escrevendo cenários para pessoas que não tem o mesmo conhecimento de negócio que você, imagine aquele marciano na sua frente e tente explicar para ele o que precisa ser feito...&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;Escrever os cenários com Gherkin é incrivelmente simples, o fato de ter poucas palavras-chave torna o modelo muito fácil de ser aprendido, e após escrever poucos cenários não é mais necessário pesquisar exemplos para se basear.&lt;/p&gt;

&lt;p&gt;Além de ser fácil, esse modelo fornece uma estrutura de escrita que quando é bem usada, diminui consideravelmente os ruídos e mal-entendidos entre o que o solicitante precisar e o que é implementado de fato.&lt;/p&gt;

&lt;p&gt;Por hoje é tudo pessoal, espero que tenham se divertido com a leitura e tenham se interessado por aprender um pouco mais sobre Gherkin, não deixe de conferir as fontes deste material.&lt;/p&gt;

&lt;p&gt;Ah, e se encontrar um alien por aí, diga que eu mandei um "Oi!".&lt;/p&gt;

&lt;h2&gt;
  
  
  Fontes:
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://cucumber.io/docs/gherkin/reference/" rel="noopener noreferrer"&gt;https://cucumber.io/docs/gherkin/reference/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://medium.com/revista-tspi/gherkin-o-dia-em-que-entendi-que-estava-escrevendo-errado-220a84520819" rel="noopener noreferrer"&gt;https://medium.com/revista-tspi/gherkin-o-dia-em-que-entendi-que-estava-escrevendo-errado-220a84520819&lt;/a&gt;&lt;/p&gt;

</description>
      <category>gratitude</category>
    </item>
  </channel>
</rss>
