{"id":73,"date":"2021-03-22T12:07:00","date_gmt":"2021-03-22T15:07:00","guid":{"rendered":"https:\/\/dumba.dev.br\/?p=73"},"modified":"2026-01-13T12:08:25","modified_gmt":"2026-01-13T15:08:25","slug":"escrever-querys-brutas-para-consulta-em-um-banco-de-dados-relacional-usando-entity-framework-core-ef-para-retornar-um-dto","status":"publish","type":"post","link":"https:\/\/dumba.dev.br\/index.php\/2021\/03\/22\/escrever-querys-brutas-para-consulta-em-um-banco-de-dados-relacional-usando-entity-framework-core-ef-para-retornar-um-dto\/","title":{"rendered":"Escrever querys brutas para consulta em um banco de dados relacional usando Entity Framework Core (EF) para retornar um DTO."},"content":{"rendered":"\n<p>Quem nunca teve problemas com Query geradas pelo&nbsp;<a href=\"https:\/\/docs.microsoft.com\/pt-br\/ef\/core\/\" target=\"_blank\" rel=\"noreferrer noopener\">Entity Framework (EF)<\/a>&nbsp;que atire a primeira pedra. Dependendo da complexidade do que se busca pode ficar muito complicado sua performance. Usar o&nbsp;<a href=\"https:\/\/docs.microsoft.com\/en-us\/ef\/core\/querying\/raw-sql\" target=\"_blank\" rel=\"noreferrer noopener\">FromSqlRaw<\/a>&nbsp;funciona, mas somente para o objeto mapeado no contexto (DbContext) e se eu quiser retornar um DTO (Data Transfer Object) ou uma mistureba de dados??<\/p>\n\n\n\n<p>\u201cMas Dumb\u00e1, usa o&nbsp;<a href=\"https:\/\/dapper-tutorial.net\/dapper\" target=\"_blank\" rel=\"noreferrer noopener\">Dapper<\/a>!! Ta reinventando a roda por qu\u00ea?\u201d Sim, Dapper resolve, mas sou nojento e quero usar o Entity \ud83d\ude42&nbsp; ou simplesmente a Arquitetura da empresa ainda n\u00e3o permite o Dapper. Dependendo do negocio somente pacotes aprovados podem ser utilizados.<\/p>\n\n\n\n<p>E por esse motivo, um amigo me perguntou outro dia como ele poderia resolver esse problema, sabendo que a empresa utilizava o entity e estava relutante a liberar outro pacote. Era simples, basta mapear o objeto no contexto e chamar o FromSqlRaw, mas ele ficou encucado com isso e queria algo mais simples, sem mapeamentos.<\/p>\n\n\n\n<p>Ai que entra o pulo do gato velho!<\/p>\n\n\n\n<p>Os caboclos das antigas sabem que por traz de tudo que abrange acesso a dados em .NET desde os prim\u00f3rdios \u00e9 o bom e velho&nbsp;<a href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/framework\/data\/adonet\/ado-net-architecture\" target=\"_blank\" rel=\"noreferrer noopener\">ADO.NET<\/a>. O que o Entity, Dapper e qualquer outro ORM ou Micro ORM faz \u00e9 encapsular o ADO.NET.<\/p>\n\n\n\n<p>Propus a esse meu amigo uma solu\u00e7\u00e3o no qual utilizo em meus QueryRepositories (Gosto de separar os reposit\u00f3rios, um para persist\u00eancia e outro para consultas, coisas de CQRS, mas isso fica pra outro artigo).<\/p>\n\n\n\n<p>A ideia do c\u00f3digo abaixo \u00e9 buscar os Providers do ADO que j\u00e1 existem no EF. Como j\u00e1 temos o contexto do EF injetado, vou acessar o banco de dados j\u00e1 configurado para o EF.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">protected IList&lt;Tdto&gt; SelectSql&lt;Tdto&gt;(string sql, params object[] parameters) where Tdto: class\n{\n    using var command = _context.Database.GetDbConnection().CreateCommand();\n    command.CommandText = sql;\n\n    foreach (var parameter in parameters)\n    {\n        command.Parameters.Add(parameter);\n    }\n\n    _context.Database.OpenConnection();\n    using var result = command.ExecuteReader();\n    return DataReaderMapToList&lt;Tdto&gt;(result);\n}<\/pre>\n\n\n\n<p>Assim eu consigo passar a consulta Sql que preciso, passo o DTO ou Classe a para ser transformada e retorno um objeto j\u00e1 mapeado usando o Generics \u201cTdto\u201d.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">private static List&lt;Tdto&gt; DataReaderMapToList&lt;Tdto&gt;(DbDataReader dr)\n{\n    List&lt;Tdto&gt; list = new List&lt;Tdto&gt;();\n\n    if (dr.HasRows)\n    {\n        while (dr.Read())\n        {\n            var dto = Activator.CreateInstance&lt;Tdto&gt;();\n            foreach (PropertyInfo prop in dto.GetType().GetProperties())\n            {\n                if (dr.GetColumnSchema().Any(x =&gt; x.ColumnName.ToUpper() == prop.Name.ToUpper()))\n                {\n                    if (!Equals(dr[prop.Name], DBNull.Value))\n                    {\n                        prop.SetValue(dto, dr[prop.Name], null);\n                    }\n                }\n            }\n            list.Add(dto);\n        }\n        return list;\n    }\n    return new List&lt;Tdto&gt;();\n}<\/pre>\n\n\n\n<p>Usando Reflection eu mapeio o retorno do DataReader para o DTO informado.<\/p>\n\n\n\n<p>Como uso o puro e velho ADO isso faz com que a performance seja muito, mas muito boa. (Depende da Query n\u00e9 mestre, se fizer um select * em 2.000.000,00 de linhas vai demorar um mocado), mas j\u00e1 em melhor que 90% das consultas do EF (Eu acho). \ud83d\ude09<\/p>\n\n\n\n<p>Mas se tiverem uma solu\u00e7\u00e3o melhor, manda ai pra mim, vamos disseminar conhecimento, pois eu n\u00e3o sei de tudo e \u00e9 sempre bom aprender.<\/p>\n\n\n\n<p>Os c\u00f3digos fontes est\u00e3o no meu&nbsp;<a href=\"https:\/\/github.com\/danilodumba\/qsLibPack\" target=\"_blank\" rel=\"noreferrer noopener\">GitHub<\/a>&nbsp;e os c\u00f3digos como s\u00e3o utilizados est\u00e3o no&nbsp;<a href=\"https:\/\/github.com\/danilodumba\/qsLibPack\/blob\/master\/src\/qsLibPack\/Repositories\/EF\/QueryRepository.cs\" target=\"_blank\" rel=\"noreferrer noopener\">qsLibPack<\/a>, pacote que utilizo para padronizar meus projetos e no&nbsp;<a href=\"https:\/\/github.com\/danilodumba\/qsLog\/blob\/master\/qslog-back\/src\/qsLog\/3%20-%20Infrastructure\/Database\/MySql\/EF\/QueryRepositories\/LogQueryRepository.cs\" target=\"_blank\" rel=\"noreferrer noopener\">qsLog<\/a>, que \u00e9 um projeto no qual utilizo muita coisa interessante como DDD, Mediator, Repository, TDD, Services e muito mais.<\/p>\n\n\n\n<p>Obrigado pela leitura e duvidas \u00e9 so mandar!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Quem nunca teve problemas com Query geradas pelo&nbsp;Entity Framework (EF)&nbsp;que atire a primeira pedra. Dependendo da complexidade do que se busca pode ficar muito complicado sua performance. Usar o&nbsp;FromSqlRaw&nbsp;funciona, mas somente para o objeto mapeado no contexto (DbContext) e se eu quiser retornar um DTO (Data Transfer Object) ou uma mistureba de dados?? \u201cMas Dumb\u00e1, [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":46,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-73","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-sem-categoria"],"_links":{"self":[{"href":"https:\/\/dumba.dev.br\/index.php\/wp-json\/wp\/v2\/posts\/73","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dumba.dev.br\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dumba.dev.br\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dumba.dev.br\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/dumba.dev.br\/index.php\/wp-json\/wp\/v2\/comments?post=73"}],"version-history":[{"count":1,"href":"https:\/\/dumba.dev.br\/index.php\/wp-json\/wp\/v2\/posts\/73\/revisions"}],"predecessor-version":[{"id":74,"href":"https:\/\/dumba.dev.br\/index.php\/wp-json\/wp\/v2\/posts\/73\/revisions\/74"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/dumba.dev.br\/index.php\/wp-json\/wp\/v2\/media\/46"}],"wp:attachment":[{"href":"https:\/\/dumba.dev.br\/index.php\/wp-json\/wp\/v2\/media?parent=73"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dumba.dev.br\/index.php\/wp-json\/wp\/v2\/categories?post=73"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dumba.dev.br\/index.php\/wp-json\/wp\/v2\/tags?post=73"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}