{"id":3331,"date":"2020-07-17T09:10:36","date_gmt":"2020-07-17T07:10:36","guid":{"rendered":"http:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/?p=3331"},"modified":"2020-07-17T09:11:27","modified_gmt":"2020-07-17T07:11:27","slug":"odata-y-como-beneficiar-nuestro-perfomance-con-entity-framework","status":"publish","type":"post","link":"https:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/odata-y-como-beneficiar-nuestro-perfomance-con-entity-framework\/","title":{"rendered":"OData y c\u00f3mo beneficiar nuestro perfomance con Entity Framework"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-3333\" src=\"http:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/wp-content\/uploads\/sites\/8\/2020\/07\/odata.jpg\" alt=\"\" width=\"1081\" height=\"775\" srcset=\"https:\/\/encaminablogs.wpenginepowered.com\/desarrollandosobresharepoint\/wp-content\/uploads\/sites\/8\/2020\/07\/odata.jpg 1081w, https:\/\/encaminablogs.wpenginepowered.com\/desarrollandosobresharepoint\/wp-content\/uploads\/sites\/8\/2020\/07\/odata-300x215.jpg 300w, https:\/\/encaminablogs.wpenginepowered.com\/desarrollandosobresharepoint\/wp-content\/uploads\/sites\/8\/2020\/07\/odata-1024x734.jpg 1024w, https:\/\/encaminablogs.wpenginepowered.com\/desarrollandosobresharepoint\/wp-content\/uploads\/sites\/8\/2020\/07\/odata-768x551.jpg 768w, https:\/\/encaminablogs.wpenginepowered.com\/desarrollandosobresharepoint\/wp-content\/uploads\/sites\/8\/2020\/07\/odata-610x437.jpg 610w\" sizes=\"auto, (max-width: 1081px) 100vw, 1081px\" \/><\/p>\n<div class=\"post\">\n<p>A la hora de hacer las consultas sobre nuestras WebApi, <strong>OData es un est\u00e1ndar propio de Microsoft<\/strong> que est\u00e1n adoptando la mayor\u00eda de API\u2019s de los productos punteros para establecer su comunicaci\u00f3n con el Front. Apps como Twitter, Facebook y naturalmente Microsoft Graph, utilizan esta forma de realizar consultas a sus objetos de negocio. Como desarrolladores, muchas veces no ponemos OData por miedo al performance que ocasiona en el Backend. \u00bfC\u00f3mo lo podemos solucionar? En este art\u00edculo vemos c\u00f3mo cuidar las consultas para evitar matar muchos gatitos y ahorrarnos esfuerzos en el desarrollo \ud83d\ude05<\/p>\n<h1><!--more--><\/h1>\n<h1 id=\"introducci\u00f3n\">Introducci\u00f3n<\/h1>\n<p>Este art\u00edculo es una continuaci\u00f3n del\u00a0<a href=\"https:\/\/blogs.encamina.com\/piensa-en-software-desarrolla-en-colores\/vitamina-tu-api-en-net-core-con-odata\/\">post<\/a>\u00a0que escribi\u00f3 mi compa\u00f1ero\u00a0<a href=\"https:\/\/twitter.com\/sparraguerra\">Sergio Parra<\/a>. As\u00ed que si no hab\u00e9is o\u00eddo nada sobre OData y c\u00f3mo empezar a utilizarlo en los desarrollos en .NET, leedlo y luego continuad por este punto \ud83d\ude42<\/p>\n<p>Una vez nos hemos le\u00eddo el art\u00edculo anterior, ya sabemos lo qu\u00e9 es OData: un est\u00e1ndar que define un conjunto de buenas pr\u00e1cticas para la construcci\u00f3n y consumo de RESTFul API.<\/p>\n<p>De todo lo que tiene Odata, centr\u00e9monos en la parte relacionada con la <strong>realizaci\u00f3n de consultas<\/strong>. A ver, levantad la mano: \u00bfen cu\u00e1ntos proyectos, en las llamadas para hacer filtros creas un objeto para indicar sobre qu\u00e9 campo o valores filtramos?\u2026 No me digas que es una tarea sencilla hacer eso. Pero ojo, \u00bfa cu\u00e1ntos nos ha pasado que, una vez instalado, surge un nuevo requerimiento y no podemos filtrar por este u otro campo? Eso, a nivel de desarrollo implica que tenemos que hacer una modificaci\u00f3n en la API y posteriormente modificar la consulta, DTO\u2019s, Test (si los hubiera). Es decir, una simple modificaci\u00f3n, implica dedicar un tiempo extra muy valioso.<\/p>\n<p>Otra de las ventajas que tiene OData respecto a nuestro desarrollo \u201cCustom\u201d es que es un est\u00e1ndar. Esto hace que <strong>cualquier developer<\/strong> (ya sea de Front\/Back) <strong>pueda entender c\u00f3mo funciona<\/strong> y pueda realizar las peticiones a la API que necesita en su desarrollo.<\/p>\n<p>Ahora bien, este \u00faltimo punto tambi\u00e9n puede ser un inconveniente dependiendo de la madurez del equipo de desarrollo.<\/p>\n<p>Pensad un supuesto en el que\u00a0 se cree un \u00fanico controlador con OData y se permita realizar cualquier filtro y consulta sobre dicha entidad. Esto puede hacer que para establecer determinada l\u00f3gica de negocio, en lugar de implementar un m\u00e9todo en el controlador con dicha l\u00f3gica, se indique que esta l\u00f3gica se haga implementando filtros con OData. Para m\u00ed, este supuesto es un mal uso de OData. S\u00ed,\u00a0 hemos dicho que nos ahorra tiempo de implementaci\u00f3n, pero esto no implica que en cada entidad tengamos que indicar sobre qu\u00e9 campos queremos filtrar y sobre todo,\u00a0 qu\u00e9 queremos mostrar.<\/p>\n<p>Imaginad un caso en el que tengamos una lista de clientes y un filtro en el que mostremos cualquier informaci\u00f3n sobre \u00e9l. Por ejemplo, informaci\u00f3n tan sustancial como el importe que nos adeuda\u2026 No creo que la mejor opci\u00f3n sea que implementemos OData y con ella poder permitir cualquier opci\u00f3n.<\/p>\n<h1 id=\"como-incorporar-odata\">C\u00f3mo incorporar OData<\/h1>\n<p>Vamos a partir de que tenemos una API de Avengers. En primer lugar vamos a configurar e <strong>instalar los paquetes Nuget<\/strong> necesarios para empezar a utilizar OData en nuestra API. En este caso nos har\u00e1 falta el siguiente paquete:<\/p>\n<div class=\"highlight\">\n<pre><code class=\"language-bash\" data-lang=\"bash\">dotnet add package Microsoft.AspNetCore.OData --version 7.4.1\r\n<\/code><\/pre>\n<\/div>\n<p>Una vez esta instalado, tocaremos el <strong>StartUp<\/strong> para a\u00f1adirle el soporte para <strong>OData. <\/strong>Para ello, en el m\u00e9todo Configure Services le indicamos que vamos a hacer uso de OData y a\u00f1adimos la siguientes l\u00edneas:<\/p>\n<div class=\"highlight\">\n<pre><code class=\"language-csharp\" data-lang=\"csharp\">   services.AddOData();\r\n   services.AddODataQueryFilter();\r\n   services.AddMvc(options =&gt;\r\n            {\r\n                options.EnableEndpointRouting = false;\r\n            });\r\n<\/code><\/pre>\n<\/div>\n<p>Ahora, dentro del m\u00e9todo Configure del mismo StartUp, substitu\u00edmos app.UseRouting() por el UseMvc(), con la siguiente configuraci\u00f3n:<\/p>\n<div class=\"highlight\">\n<pre><code class=\"language-csharp\" data-lang=\"csharp\">   app.UseMvc(routeBuilder =&gt;;\r\n   {\r\n      routeBuilder.EnableDependencyInjection();\r\n      routeBuilder.Select().Filter().OrderBy().Expand().Count().MaxTop(10); \r\n      routeBuilder.MapODataServiceRoute(\"api\", \"api\", GetEdmModel(app.ApplicationServices));\r\n   });\r\n<\/code><\/pre>\n<\/div>\n<p>Estas l\u00edneas de c\u00f3digo lo que hacen es:<\/p>\n<ul>\n<li>Activar la inyecci\u00f3n de Dependencias<\/li>\n<li>Ver qu\u00e9 m\u00e9todos de OData vamos a permitir: Select, Filter, OrderBy, Expand, Count, Top..<\/li>\n<li>Mapear OData con nuestro modelo. ^Para ello nos creamos el m\u00e9todo GetEdm que tiene el siguiente c\u00f3digo:<\/li>\n<\/ul>\n<div class=\"highlight\">\n<pre><code class=\"language-csharp\" data-lang=\"csharp\">    private static IEdmModel GetEdmModel(IServiceProvider serviceProvider)\r\n    {\r\n        ODataModelBuilder builder = new ODataConventionModelBuilder(serviceProvider);\r\n        builder.EntitySet&lt;Avenger&gt;(\"Avenger\")\r\n                                            .EntityType\r\n                                            .Filter()\r\n                                            .Count()\r\n                                            .Expand()\r\n                                            .OrderBy()\r\n                                            .Page()\r\n                                            .Select();\r\n        return builder.GetEdmModel();\r\n    }\r\n<\/code><\/pre>\n<\/div>\n<p>Una vez tenemos el arranque configurado, vamos a <strong>tunear el controlador. <\/strong>Para ello, en primer lugar cambiamos el ControllerBase por el ODataController, quedando nuestro Controller de la siguiente forma:<\/p>\n<div class=\"highlight\">\n<pre><code class=\"language-csharp\" data-lang=\"csharp\"> public class AvengerController : ODataController\r\n {\r\n     ...\r\n }\r\n<\/code><\/pre>\n<\/div>\n<p>Posteriormente vamos a a\u00f1adir unos decoradores al m\u00e9todo, para lo que usaremos OData. Imaginad que tenemos un m\u00e9todo que nos devuelve todos los Avengers, quedando de la siguiente forma:<\/p>\n<div class=\"highlight\">\n<pre><code class=\"language-csharp\" data-lang=\"csharp\">[ODataRoute]\r\n[EnableQuery(PageSize = 20, AllowedQueryOptions = AllowedQueryOptions.All)]\r\n[HttpGet]\r\npublic async Task&lt;IActionResult&gt; Get()\r\n    {\r\n        var result = await avengerDomain.GetAllAsync();\r\n        if (result != null)\r\n        {\r\n            return Ok(result);\r\n        }\r\n        else\r\n        {\r\n            return NotFound();\r\n        } \r\n    }\r\n<\/code><\/pre>\n<\/div>\n<p>Si arrancamos nuestra API e invocamos al siguiente m\u00e9todo localhost\/api\/avenger, vemos que nos carga todos los \u00edtems que tenemos en Avengers.<img decoding=\"async\" src=\"https:\/\/www.theavenger.dev\/posts\/images\/odata-entity\/RequestNormal.PNG\" alt=\"request normal\" \/><\/p>\n<p>Ahora s\u00ed,\u00a0 usamos la <strong>sintaxis de OData para filtrar<\/strong>. Si tenemos un Avenger que se llama Hulk, por ejemplo,\u00a0 hacemos localhost\/api\/avenger?filter=$name eq \u2018Hulk\u2019<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.theavenger.dev\/posts\/images\/odata-entity\/RequestOdata.PNG\" alt=\"request odata\" \/><\/p>\n<h1 id=\"cu\u00e1l-es-el-problema\">\u00bfCu\u00e1l es el problema?<\/h1>\n<p>A nivel de la representaci\u00f3n de los datos la devoluci\u00f3n es la correcta, pero ahora bien, si analizamos las tripas y ponemos un punto de parada antes de que devolvamos los resultados, veremos lo siguiente:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.theavenger.dev\/posts\/images\/odata-entity\/depurar.gif\" alt=\"resultado odata\" \/><\/p>\n<p>Como pod\u00e9is ver, a pesar de que solamente hemos pedido un \u00fanico registro, se est\u00e1 trayendo toda la informaci\u00f3n de la tabla y despu\u00e9s, filtra los datos que he pedido. En mi opini\u00f3n,<strong> esta opci\u00f3n no es la m\u00e1s optima<\/strong>. Imaginad que tenemos una tabla con cantidad elevada de registros y solo queremos devolver dos. Por un lado, es posible que esa consulta pueda tener una <strong>penalizaci\u00f3n<\/strong> en cuanto a rendimiento y, por otro lado, tampoco tiene sentido hacer los filtros en el servidor cuando lo puede\/debe hacer la base de datos.<\/p>\n<h1 id=\"como-se-puede-solucionar-con-odata\">\u00bfC\u00f3mo se puede solucionar con OData?<\/h1>\n<p>En primer lugar, nos hemos olvidado de un par\u00e1metro que se puede pasar en el controlador, y en el cual podemos tener la consulta que se ha realizado desde la petici\u00f3n, es decir, tenemos un objeto donde est\u00e1 nuestra consulta y c\u00f3mo utilizarla. Este objeto es <a href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/api\/microsoft.aspnet.odata.query.odataqueryoptions?view=odata-aspnetcore-7.0\">ODataQueryOptions filter.<\/a> Lo a\u00f1adimos como par\u00e1metro en nuestro controlador y volvemos a ejecutar la consulta:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.theavenger.dev\/posts\/images\/odata-entity\/ODataQueryOptions.gif\" alt=\"resultado odata\" \/><\/p>\n<p>Si analizamos el contenido de ese objeto, observamos que, por un lado, tiene en las propiedades cada uno de los elementos que contiene el Filter, Top, Count, etc.. y tiene un m\u00e9todo <strong>ApplyTo<\/strong>. El m\u00e9todo ApplyTo tiene como par\u00e1metro de entrada un objeto IQueryable y, sobre este m\u00e9todo, se aplica el filtro que el usuario ha realizado a la Api. Muchas veces implementamos un patr\u00f3n repositorio en el que tenemos unos m\u00e9todos que directamente nos devuelven un m\u00e9todo IList.<\/p>\n<p>Un ejemplo de Patr\u00f3n repositorio ser\u00eda el siguiente c\u00f3digo:<\/p>\n<div class=\"highlight\">\n<pre><code class=\"language-csharp\" data-lang=\"csharp\"> public interface IRepositoryBase&lt;T, U&gt; : IDisposable where T : Base&lt;U&gt;, new() where U : unmanaged\r\n    {\r\n        T Add(T entity);\r\n        T GetById(U id);\r\n        T GetById(U id, Func&lt;IQueryable&lt;T&gt;, IIncludableQueryable&lt;T, object&gt;&gt; includes);\r\n        IList&lt;T&gt; Get(Expression&lt;Func&lt;T, bool&gt;&gt; filter);\r\n        IList&lt;T&gt; Get(Expression&lt;Func&lt;T, bool&gt;&gt; filter, Func&lt;IQueryable&lt;T&gt;, IQueryable&lt;T&gt;&gt; func);\r\n        bool Update(T entity);\r\n        bool Delete(U id);        \r\n    }\r\n<\/code><\/pre>\n<\/div>\n<p>Muchas veces no entendemos la diferencia entre las interfaces IQueryable, IList, ICollection e IEnumerable y los motivos por los que usar unos u otros. Podr\u00edamos definir cada una de ellas de la siguiente forma:<\/p>\n<p><strong>IEnumerable<\/strong> =&gt; Es la interfaz b\u00e1sica y de la que heredan el resto de interfaces. Puedes iterar a trav\u00e9s de cada elemento del IEnumerable. No puedes editar los elementos como a\u00f1adir, borrar, actualizar, etc. En su lugar, s\u00f3lo usas un contenedor para contener una lista de elementos. Es el tipo m\u00e1s b\u00e1sico de contenedor de listas. Todo lo que obtienes en un IEnumerable es un enumerador que ayuda a iterar sobre los elementos. Un IEnumerable no contiene ni siquiera el conteo de los elementos de la lista, en su lugar, tienes que iterar sobre los elementos para obtener el conteo de los elementos. Soporta el filtrado de elementos usando la cl\u00e1usula where.<\/p>\n<p><strong>ICollection<\/strong> =&gt; Es la m\u00e1s b\u00e1sica de las interfaces que hemos enumerado. Es una interfaz enumerable que soporta un Conteo, y eso es todo. IList incluye todo lo que es ICollection, pero tambi\u00e9n soporta a\u00f1adir y quitar elementos, recuperar elementos por \u00edndice, etc.<\/p>\n<p><strong>IQueryable<\/strong>\u00a0=&gt; Es una interfaz enumerable que soporta LINQ. Siempre se puede crear un IQueryable a partir de un IList y usar LINQ a Objetos, pero tambi\u00e9n se encuentra el IQueryable usado para la ejecuci\u00f3n diferida de sentencias SQL en LINQ a SQL y LINQ a Entidades.<\/p>\n<p>Partiendo de esta definici\u00f3n, est\u00e1 claro que al Repositorio Base que hemos planteado le faltan unos m\u00e9todos IQueryable. Principalmente, porque en el momento en el que lancemos una .ToList() se va a ejecutar la consulta, y est\u00e1 claro que no es lo mismo hacer una consulta con todos los \u00edtems de la tabla, que hacer una consulta solo con la informaci\u00f3n que se necesita. Por este motivo, a\u00f1adimos al patr\u00f3n repositorio anterior, los siguientes m\u00e9todos:<\/p>\n<div class=\"highlight\">\n<pre><code class=\"language-csharp\" data-lang=\"csharp\">        IQueryable&lt;T&gt; ListAll();\r\n        IQueryable&lt;T&gt; ListAll(Func&lt;IQueryable&lt;T&gt;, IQueryable&lt;T&gt;&gt; func);\r\n<\/code><\/pre>\n<\/div>\n<p>Una vez tenemos a\u00f1adido nuestro el m\u00e9todo que nos devuelve el IQueryable lo que debemos de hacer es modificar nuestro m\u00e9todo de dominio. Para ello en primer lugar le pasaremos el objeto Filter donde tenemos la consulta que se ha pedido a la API. Quedando nuestro m\u00e9todo de la siguiente forma:<\/p>\n<div class=\"highlight\">\n<pre><code class=\"language-csharp\" data-lang=\"csharp\">public IList&lt;Avenger&gt; GetAll(ODataQueryOptions&lt;Avenger&gt; filter)\r\n{\r\n    var avenger = (IEnumerable&lt;Avenger&gt;)filter.ApplyTo(avengerRepository.ListAll());            \r\n    return avenger.ToList();            \r\n}\r\n<\/code><\/pre>\n<\/div>\n<p>Si ahora nos pica un poco la curiosidad y analizamos las peticiones que hacemos a la base de datos con este cambio, podemos ver que la consulta, ahora es tal y como la hemos pedido en la API, optimizando la consulta:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.theavenger.dev\/posts\/images\/odata-entity\/query.PNG\" alt=\"consulta insight\" \/><\/p>\n<h2 id=\"alguna-cosa-m\u00e1s\">\u00bfAlguna cosa m\u00e1s?<\/h2>\n<p>Esto no es todo. Si mir\u00e1is por encima todas las posibilidades que trae OData, nos ofrece la opci\u00f3n de traernos solo los datos que realmente necesitamos de la clase. Si establecemos una instrucci\u00f3n Select en la petici\u00f3n de OData y forzamos el tipo en el que queremos devolver, se produce un error, debido a que no coinciden los tipos. Por ejemplo, si realizamos la siguiente instrucci\u00f3n:<\/p>\n<div class=\"highlight\">\n<pre><code class=\"language-bash\" data-lang=\"bash\">https:\/\/localhost:44339\/api\/avenger?$name=name&amp;$filter=name eq'Hulk'\r\n<\/code><\/pre>\n<\/div>\n<p>Se producir\u00e1 el siguiente error:<img decoding=\"async\" src=\"https:\/\/www.theavenger.dev\/posts\/images\/odata-entity\/ErrorOdata.PNG\" alt=\"error Odata\" \/><\/p>\n<h3 id=\"como-lo-podemos-solucionarlo\">\u00bfC\u00f3mo podemos solucionarlo?<\/h3>\n<p>Lo primero que nos viene a la cabeza es no permitir la instrucci\u00f3n Select en OData (muerto el perro se acabo la rabia). Pero una vez se nos pasa el cabreo por el error, tenemos que ver c\u00f3mo solucionarlo \u00bfY se puede solucionar? S\u00ed, incluso podemos cambiar la devoluci\u00f3n por un tipo Dynamic. No entrar\u00e9 a si conviene usarlo o no, o si es mejor o peor a nivel de ejecuci\u00f3n, pero partiendo de que vamos a devolver datos dependiendo de las necesidades que tengan los usuarios, un Dynamic no me parece una mala opci\u00f3n. Como dice algui\u00e9n muy cercano a m\u00ed \u00absiempre estamos decidiendo la opci\u00f3n menos mala\u00bb, pero eso para otro momento \ud83d\ude09 El m\u00e9todo quedar\u00eda de la siguiente forma:<\/p>\n<div class=\"highlight\">\n<pre><code class=\"language-csharp\" data-lang=\"csharp\">public IList&lt;dynamic&gt; GetAll(ODataQueryOptions&lt;Avenger&gt; filter)\r\n{\r\n    var avenger = (IEnumerable&lt;dynamic&gt;)filter.ApplyTo(avengerRepository.ListAll());            \r\n    return avenger.ToList();            \r\n}\r\n<\/code><\/pre>\n<\/div>\n<h1 id=\"resumen\">Resumen<\/h1>\n<p>OData es una opci\u00f3n bastante f\u00e1cil de a\u00f1adir en tus desarrollos, pero las balas de plata solo existen en las pel\u00edculas y como en todo, hay que saber c\u00f3mo cuidar determinados aspectos del Perfomance de la base de datos y sobre todo, conocer todas las capacidades que tiene el lenguaje como las librer\u00edas cuandoe hacemos uso de ellas.<\/p>\n<p>Happy Codding \ud83d\ude42<\/p>\n<\/div>\n<p>&nbsp;<\/p>\n<footer>\n<div>\u00a9<\/div>\n<\/footer>\n<!-- AddThis Advanced Settings generic via filter on the_content --><!-- AddThis Share Buttons generic via filter on the_content --><span class=\"et_bloom_bottom_trigger\"><\/span>","protected":false},"excerpt":{"rendered":"<p>A la hora de hacer las consultas sobre nuestras WebApi, OData es un est\u00e1ndar propio de Microsoft que est\u00e1n adoptando la mayor\u00eda de API\u2019s de los productos punteros para establecer su comunicaci\u00f3n con el Front. Apps como Twitter, Facebook y &hellip; <a href=\"https:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/odata-y-como-beneficiar-nuestro-perfomance-con-entity-framework\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><!-- AddThis Advanced Settings generic via filter on get_the_excerpt --><!-- AddThis Share Buttons generic via filter on get_the_excerpt --><\/p>\n","protected":false},"author":8,"featured_media":3333,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[119,5],"tags":[],"class_list":["post-3331","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-azure-2","category-desarrollo"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v18.2.1 (Yoast SEO v28.3) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>OData y c\u00f3mo beneficiar nuestro perfomance con Entity Framework | ENCAMINA<\/title>\n<meta name=\"description\" content=\"En este art\u00edculo vemos c\u00f3mo cuidar las consultas para evitar matar muchos gatitos y ahorrarnos esfuerzos en el desarrollo.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.theavenger.dev\/posts\/odata-dotnet-entityframework\/\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:title\" content=\"OData y c\u00f3mo beneficiar nuestro perfomance con Entity Framework | ENCAMINA\" \/>\n<meta name=\"twitter:description\" content=\"En este art\u00edculo vemos c\u00f3mo cuidar las consultas para evitar matar muchos gatitos y ahorrarnos esfuerzos en el desarrollo.\" \/>\n<meta name=\"twitter:image\" content=\"https:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/wp-content\/uploads\/sites\/8\/2020\/07\/odata.jpg\" \/>\n<meta name=\"twitter:label1\" content=\"Escrito por\" \/>\n\t<meta name=\"twitter:data1\" content=\"Adri\u00e1n D\u00edaz\" \/>\n\t<meta name=\"twitter:label2\" content=\"Tiempo de lectura\" \/>\n\t<meta name=\"twitter:data2\" content=\"10 minutos\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.theavenger.dev\\\/posts\\\/odata-dotnet-entityframework\\\/#article\",\"isPartOf\":{\"@id\":\"http:\\\/\\\/blogs.encamina.com\\\/desarrollandosobresharepoint\\\/odata-y-como-beneficiar-nuestro-perfomance-con-entity-framework\\\/\"},\"author\":{\"name\":\"Adri\u00e1n D\u00edaz\",\"@id\":\"https:\\\/\\\/blogs.encamina.com\\\/desarrollandosobresharepoint\\\/#\\\/schema\\\/person\\\/c9bfaede1bfba9564bb7f500788782bb\"},\"headline\":\"OData y c\u00f3mo beneficiar nuestro perfomance con Entity Framework\",\"datePublished\":\"2020-07-17T07:10:36+00:00\",\"dateModified\":\"2020-07-17T07:11:27+00:00\",\"mainEntityOfPage\":{\"@id\":\"http:\\\/\\\/blogs.encamina.com\\\/desarrollandosobresharepoint\\\/odata-y-como-beneficiar-nuestro-perfomance-con-entity-framework\\\/\"},\"wordCount\":1821,\"commentCount\":0,\"image\":{\"@id\":\"https:\\\/\\\/www.theavenger.dev\\\/posts\\\/odata-dotnet-entityframework\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/blogs.encamina.com\\\/desarrollandosobresharepoint\\\/wp-content\\\/uploads\\\/sites\\\/8\\\/2020\\\/07\\\/odata.jpg\",\"articleSection\":[\"Azure\",\"desarrollo\"],\"inLanguage\":\"es\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.theavenger.dev\\\/posts\\\/odata-dotnet-entityframework\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"http:\\\/\\\/blogs.encamina.com\\\/desarrollandosobresharepoint\\\/odata-y-como-beneficiar-nuestro-perfomance-con-entity-framework\\\/\",\"url\":\"https:\\\/\\\/www.theavenger.dev\\\/posts\\\/odata-dotnet-entityframework\\\/\",\"name\":\"OData y c\u00f3mo beneficiar nuestro perfomance con Entity Framework | ENCAMINA\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/blogs.encamina.com\\\/desarrollandosobresharepoint\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.theavenger.dev\\\/posts\\\/odata-dotnet-entityframework\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.theavenger.dev\\\/posts\\\/odata-dotnet-entityframework\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/blogs.encamina.com\\\/desarrollandosobresharepoint\\\/wp-content\\\/uploads\\\/sites\\\/8\\\/2020\\\/07\\\/odata.jpg\",\"datePublished\":\"2020-07-17T07:10:36+00:00\",\"dateModified\":\"2020-07-17T07:11:27+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/blogs.encamina.com\\\/desarrollandosobresharepoint\\\/#\\\/schema\\\/person\\\/c9bfaede1bfba9564bb7f500788782bb\"},\"description\":\"En este art\u00edculo vemos c\u00f3mo cuidar las consultas para evitar matar muchos gatitos y ahorrarnos esfuerzos en el desarrollo.\",\"inLanguage\":\"es\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.theavenger.dev\\\/posts\\\/odata-dotnet-entityframework\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\\\/\\\/www.theavenger.dev\\\/posts\\\/odata-dotnet-entityframework\\\/#primaryimage\",\"url\":\"https:\\\/\\\/blogs.encamina.com\\\/desarrollandosobresharepoint\\\/wp-content\\\/uploads\\\/sites\\\/8\\\/2020\\\/07\\\/odata.jpg\",\"contentUrl\":\"https:\\\/\\\/blogs.encamina.com\\\/desarrollandosobresharepoint\\\/wp-content\\\/uploads\\\/sites\\\/8\\\/2020\\\/07\\\/odata.jpg\",\"width\":1081,\"height\":775},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/blogs.encamina.com\\\/desarrollandosobresharepoint\\\/#website\",\"url\":\"https:\\\/\\\/blogs.encamina.com\\\/desarrollandosobresharepoint\\\/\",\"name\":\"Desarrollando sobre SharePoint\",\"description\":\"Arquitectura, buenas pr\u00e1cticas y desarrollo sobre la nueva herramienta de Microsoft SharePoint 2016\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/blogs.encamina.com\\\/desarrollandosobresharepoint\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"es\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/blogs.encamina.com\\\/desarrollandosobresharepoint\\\/#\\\/schema\\\/person\\\/c9bfaede1bfba9564bb7f500788782bb\",\"name\":\"Adri\u00e1n D\u00edaz\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/fe10b9eaf8ce4565ec75fba5a0d121c16186696e515cad2bedd42f6cf54e2007?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/fe10b9eaf8ce4565ec75fba5a0d121c16186696e515cad2bedd42f6cf54e2007?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/fe10b9eaf8ce4565ec75fba5a0d121c16186696e515cad2bedd42f6cf54e2007?s=96&d=mm&r=g\",\"caption\":\"Adri\u00e1n D\u00edaz\"},\"description\":\"Adri\u00e1n D\u00edaz es Ingeniero Inform\u00e1tico por la Universidad Polit\u00e9cnica de Valencia. Es MVP de Microsoft en la categor\u00eda Office Development desde 2014, MCPD de SharePoint 2010, Microsoft Active Profesional y Microsoft Comunity Contribuitor 2012. Cofundador del grupo de usuarios de SharePoint de Levante LevaPoint. Lleva desarrollando con tecnolog\u00edas Microsoft m\u00e1s de 10 a\u00f1os y desde hace 3 a\u00f1os est\u00e1 centrado en el desarrollo sobre SharePoint. Actualmente es Software &amp; Cloud Architect Lead en ENCAMINA.\",\"url\":\"https:\\\/\\\/blogs.encamina.com\\\/desarrollandosobresharepoint\\\/author\\\/desarrollandosobresharepoint\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"OData y c\u00f3mo beneficiar nuestro perfomance con Entity Framework | ENCAMINA","description":"En este art\u00edculo vemos c\u00f3mo cuidar las consultas para evitar matar muchos gatitos y ahorrarnos esfuerzos en el desarrollo.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.theavenger.dev\/posts\/odata-dotnet-entityframework\/","twitter_card":"summary_large_image","twitter_title":"OData y c\u00f3mo beneficiar nuestro perfomance con Entity Framework | ENCAMINA","twitter_description":"En este art\u00edculo vemos c\u00f3mo cuidar las consultas para evitar matar muchos gatitos y ahorrarnos esfuerzos en el desarrollo.","twitter_image":"https:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/wp-content\/uploads\/sites\/8\/2020\/07\/odata.jpg","twitter_misc":{"Escrito por":"Adri\u00e1n D\u00edaz","Tiempo de lectura":"10 minutos"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.theavenger.dev\/posts\/odata-dotnet-entityframework\/#article","isPartOf":{"@id":"http:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/odata-y-como-beneficiar-nuestro-perfomance-con-entity-framework\/"},"author":{"name":"Adri\u00e1n D\u00edaz","@id":"https:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/#\/schema\/person\/c9bfaede1bfba9564bb7f500788782bb"},"headline":"OData y c\u00f3mo beneficiar nuestro perfomance con Entity Framework","datePublished":"2020-07-17T07:10:36+00:00","dateModified":"2020-07-17T07:11:27+00:00","mainEntityOfPage":{"@id":"http:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/odata-y-como-beneficiar-nuestro-perfomance-con-entity-framework\/"},"wordCount":1821,"commentCount":0,"image":{"@id":"https:\/\/www.theavenger.dev\/posts\/odata-dotnet-entityframework\/#primaryimage"},"thumbnailUrl":"https:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/wp-content\/uploads\/sites\/8\/2020\/07\/odata.jpg","articleSection":["Azure","desarrollo"],"inLanguage":"es","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.theavenger.dev\/posts\/odata-dotnet-entityframework\/#respond"]}]},{"@type":"WebPage","@id":"http:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/odata-y-como-beneficiar-nuestro-perfomance-con-entity-framework\/","url":"https:\/\/www.theavenger.dev\/posts\/odata-dotnet-entityframework\/","name":"OData y c\u00f3mo beneficiar nuestro perfomance con Entity Framework | ENCAMINA","isPartOf":{"@id":"https:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.theavenger.dev\/posts\/odata-dotnet-entityframework\/#primaryimage"},"image":{"@id":"https:\/\/www.theavenger.dev\/posts\/odata-dotnet-entityframework\/#primaryimage"},"thumbnailUrl":"https:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/wp-content\/uploads\/sites\/8\/2020\/07\/odata.jpg","datePublished":"2020-07-17T07:10:36+00:00","dateModified":"2020-07-17T07:11:27+00:00","author":{"@id":"https:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/#\/schema\/person\/c9bfaede1bfba9564bb7f500788782bb"},"description":"En este art\u00edculo vemos c\u00f3mo cuidar las consultas para evitar matar muchos gatitos y ahorrarnos esfuerzos en el desarrollo.","inLanguage":"es","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.theavenger.dev\/posts\/odata-dotnet-entityframework\/"]}]},{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/www.theavenger.dev\/posts\/odata-dotnet-entityframework\/#primaryimage","url":"https:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/wp-content\/uploads\/sites\/8\/2020\/07\/odata.jpg","contentUrl":"https:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/wp-content\/uploads\/sites\/8\/2020\/07\/odata.jpg","width":1081,"height":775},{"@type":"WebSite","@id":"https:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/#website","url":"https:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/","name":"Desarrollando sobre SharePoint","description":"Arquitectura, buenas pr\u00e1cticas y desarrollo sobre la nueva herramienta de Microsoft SharePoint 2016","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"es"},{"@type":"Person","@id":"https:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/#\/schema\/person\/c9bfaede1bfba9564bb7f500788782bb","name":"Adri\u00e1n D\u00edaz","image":{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/secure.gravatar.com\/avatar\/fe10b9eaf8ce4565ec75fba5a0d121c16186696e515cad2bedd42f6cf54e2007?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/fe10b9eaf8ce4565ec75fba5a0d121c16186696e515cad2bedd42f6cf54e2007?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/fe10b9eaf8ce4565ec75fba5a0d121c16186696e515cad2bedd42f6cf54e2007?s=96&d=mm&r=g","caption":"Adri\u00e1n D\u00edaz"},"description":"Adri\u00e1n D\u00edaz es Ingeniero Inform\u00e1tico por la Universidad Polit\u00e9cnica de Valencia. Es MVP de Microsoft en la categor\u00eda Office Development desde 2014, MCPD de SharePoint 2010, Microsoft Active Profesional y Microsoft Comunity Contribuitor 2012. Cofundador del grupo de usuarios de SharePoint de Levante LevaPoint. Lleva desarrollando con tecnolog\u00edas Microsoft m\u00e1s de 10 a\u00f1os y desde hace 3 a\u00f1os est\u00e1 centrado en el desarrollo sobre SharePoint. Actualmente es Software &amp; Cloud Architect Lead en ENCAMINA.","url":"https:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/author\/desarrollandosobresharepoint\/"}]}},"_links":{"self":[{"href":"https:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/wp-json\/wp\/v2\/posts\/3331","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/wp-json\/wp\/v2\/users\/8"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/wp-json\/wp\/v2\/comments?post=3331"}],"version-history":[{"count":0,"href":"https:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/wp-json\/wp\/v2\/posts\/3331\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/wp-json\/wp\/v2\/media\/3333"}],"wp:attachment":[{"href":"https:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/wp-json\/wp\/v2\/media?parent=3331"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/wp-json\/wp\/v2\/categories?post=3331"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.encamina.com\/desarrollandosobresharepoint\/wp-json\/wp\/v2\/tags?post=3331"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}