{"id":2015,"date":"2018-09-22T21:41:26","date_gmt":"2018-09-22T21:41:26","guid":{"rendered":"https:\/\/obioberoi.com\/?p=2015"},"modified":"2019-02-20T15:17:54","modified_gmt":"2019-02-20T15:17:54","slug":"query-types-in-ef-core","status":"publish","type":"post","link":"https:\/\/obioberoi.com\/?p=2015","title":{"rendered":"Query Types in EF Core"},"content":{"rendered":"<p>If you have been using Entity Framework 6.x or EF Core, then you are already familiar with Entities and its usage.<\/p>\n<p><em>Query Types<\/em> is a new addition to EF Core 2.1 which you can refer to Entities as its cousin.<\/p>\n<h2>What are some of the Use Cases<\/h2>\n<ul>\n<li>Is used when working with entities with <strong>no key<\/strong> propertie(s) defined, may it be a Table, Stored Procedure or a View<\/li>\n<li>Is used when mapping to queries specified in the model<\/li>\n<li>Is used for ad hoc queries where changes are not tracked in <em>DbContext.\u00a0<\/em>In other words, queries that are strictly read-only<\/li>\n<\/ul>\n<h2>So let&#8217;s get Started<\/h2>\n<p>First let&#8217;s define the two POCO classes. Each of these classes below maps to the tables in the database.<\/p>\n<pre>public class BaseAggr\r\n    {\r\n        public long BaseAggrId { get; set; }\r\n        [Display(Name = \"Portfolio ID\")]\r\n        public string PortfolioId { get; set; }\r\n\r\n        [Display(Name = \"Scenario ID\")]\r\n        public long? ScenarioId { get; set; }\r\n\r\n        [Display(Name = \"Sum Pnl\")]\r\n        public double? SumPnl { get; set; }\r\n\r\n        [Display(Name = \"Business Date\")]\r\n        [DataType(DataType.Date)]\r\n        public DateTime? BusinessDate { get; set; }\r\n    }\r\n<\/pre>\n<pre>    public class WhatIfAggr\r\n    {\r\n        public long WhatifAggrId { get; set; }\r\n\r\n        [Display(Name=\"Portfolio ID\")]\r\n        public string PortfolioId { get; set; }\r\n\r\n        [Display(Name =\"Scenario ID\")]\r\n        public long? ScenarioId { get; set; }\r\n\r\n        [Display(Name =\"Sum PnL\")]\r\n        public double? SumPnl { get; set; }\r\n\r\n        [Display(Name =\"Business Date\")]\r\n        [DataType(DataType.Date)]\r\n        public DateTime? BusinessDate { get; set; }\r\n    }\r\n<\/pre>\n<p>Next, let&#8217;s create a database view. As you can tell from the query below that it&#8217;s using Common Table Expression to form a result set.<\/p>\n<pre>CREATE OR ALTER VIEW [dbo].[vwVarByPortfolios] AS\r\nSELECT * FROM \r\n(SELECT portfolio_id, scenario_id as scenario_id, sum_pnl as var_pnl \r\n\tFROM (SELECT portfolio_id,scenario_id, sum_pnl, RANK() OVER (PARTITION BY portfolio_id ORDER BY sum_pnl DESC) AS pnl_rank FROM base_aggr) AS Agg\r\n\tWHERE pnl_rank = 98\r\n) AS A\tINNER JOIN\r\n\t\r\n(SELECT portfolio_id AS wi_portfolio_id, scenario_id AS wi_scenario_id, sum_pnl AS wi_var_pnl \r\n\tFROM (SELECT portfolio_id,scenario_id, sum_pnl, RANK() OVER (PARTITION BY portfolio_id ORDER BY sum_pnl desc) AS pnl_rank from whatif_aggr) AS Agg\r\n\tWHERE pnl_rank = 98\r\n ) AS X\r\n ON portfolio_id = wi_portfolio_id;\r\nGO<\/pre>\n<p>In addition to the classes above, you would also need a class for Query Type to hold results from the database view like so:<\/p>\n<pre>public class PortfolioView\r\n{\r\npublic string PortfolioID { get; set; }\r\npublic long ScenarioID { get; set; }\r\npublic double VarPnl { get; set; }\r\npublic string WiPortfolioID { get; set; }\r\npublic long WiScenarioID { get; set; }\r\npublic double WiVarPnl { get; set; }\r\n}\r\n<\/pre>\n<p>Next, we will create a DbQuery property in the DbContext class in order for it to be recognized as a query type.<\/p>\n<pre>public <strong>DbQuery<\/strong> PortfolioView { get; private set; }\r\n<\/pre>\n<p>Next, we will write a fluent API in DbConext&#8217;s OnModelCreating method to map the view to the Query Type i.e. <strong>vwVarByPortfolios<\/strong>. The &#8220;<em>ToView<\/em>&#8221; extension method is used to configure the mapping especially when a relational database is being targeted.<\/p>\n<pre>modelBuilder.<strong>Query()<\/strong>.<strong>ToView<\/strong>(\"vwVarByPortfolios\")\r\n                .Property(p =&gt; p.PortfolioID).HasColumnName(\"portfolio_id\");\r\n\r\n            modelBuilder.Query().ToView(\"vwVarByPortfolios\")\r\n                .Property(p =&gt; p.ScenarioID).HasColumnName(\"scenario_id\");\r\n\r\n            modelBuilder.Query().ToView(\"vwVarByPortfolios\")\r\n                .Property(p =&gt; p.VarPnl).HasColumnName(\"var_pnl\");\r\n\r\n            modelBuilder.Query().ToView(\"vwVarByPortfolios\")\r\n                .Property(p =&gt; p.WiPortfolioID).HasColumnName(\"wi_portfolio_id\");\r\n\r\n            modelBuilder.Query().ToView(\"vwVarByPortfolios\")\r\n                .Property(p =&gt; p.WiScenarioID).HasColumnName(\"wi_scenario_id\");\r\n\r\n            modelBuilder.Query().ToView(\"vwVarByPortfolios\")\r\n                .Property(p =&gt; p.WiVarPnl).HasColumnName(\"wi_var_pnl\");\r\n<\/pre>\n<p style=\"text-align: left;\">Please note, DbQuery does not require a primary key to be defined unlike its DbSet&lt;T&gt; counterpart. The Id&#8217;s are being used here just because they are needed.<\/p>\n<h2>What you cannot Do:<\/h2>\n<p>Couple things worth noting is that in this version i.e. EF Core 2.2, EF Core does not allow Views to be created in the database when migrations are run. Conversely, you cannot reverse engineer views yet. This will most likely be available in the future version of EF Core i.e. 3.0. Here&#8217;s the EF Core <a href=\"https:\/\/docs.microsoft.com\/en-us\/ef\/core\/what-is-new\/roadmap\">Roadmap<\/a> in case you wish you know further.<\/p>\n<p>Lastly, you can query the database view in your console app or a Web App, although in this case, the latter is being used along with Razor Pages.<\/p>\n<pre> public class PortfolioModel : PageModel\r\n    {\r\n        private readonly DataAggr.Models.DataAggrContext _context;\r\n\r\n        public PortfolioModel(DataAggrContext context)\r\n        {\r\n            _context = context;\r\n        }\r\n\r\n        [BindProperty]\r\n        public IList PortfolioView { get; set; }\r\n\r\n        public async Task OnGetAsync()\r\n        {\r\n            PortfolioView = await _context.Query()\r\n                .ToListAsync();\r\n        }\r\n    }\r\n<\/pre>\n<p>A quick snapshot of the output of the View from inside SQL Management Studio.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2037\" src=\"https:\/\/obioberoi.com\/wp-content\/uploads\/2019\/02\/SqlView-1.jpg\" alt=\"\" width=\"570\" height=\"345\" srcset=\"https:\/\/obioberoi.com\/wp-content\/uploads\/2019\/02\/SqlView-1.jpg 570w, https:\/\/obioberoi.com\/wp-content\/uploads\/2019\/02\/SqlView-1-300x182.jpg 300w\" sizes=\"auto, (max-width: 570px) 100vw, 570px\" \/><\/p>\n<p>Output on a Razor Page in ASP.NET Core.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-large wp-image-2036\" src=\"https:\/\/obioberoi.com\/wp-content\/uploads\/2019\/02\/PortfolioView-1024x583.jpg\" alt=\"\" width=\"640\" height=\"364\" srcset=\"https:\/\/obioberoi.com\/wp-content\/uploads\/2019\/02\/PortfolioView-1024x583.jpg 1024w, https:\/\/obioberoi.com\/wp-content\/uploads\/2019\/02\/PortfolioView-300x171.jpg 300w, https:\/\/obioberoi.com\/wp-content\/uploads\/2019\/02\/PortfolioView-768x437.jpg 768w, https:\/\/obioberoi.com\/wp-content\/uploads\/2019\/02\/PortfolioView.jpg 1105w\" sizes=\"auto, (max-width: 640px) 100vw, 640px\" \/><\/p>\n<p>Hope you found the article useful!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>If you have been using Entity Framework 6.x or EF Core, then you are already familiar with Entities and its usage. Query Types is a new addition to EF Core 2.1 which you can refer to Entities as its cousin. &hellip; <a href=\"https:\/\/obioberoi.com\/?p=2015\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2,7],"tags":[],"class_list":["post-2015","post","type-post","status-publish","format-standard","hentry","category-net","category-orm"],"_links":{"self":[{"href":"https:\/\/obioberoi.com\/index.php?rest_route=\/wp\/v2\/posts\/2015","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/obioberoi.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/obioberoi.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/obioberoi.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/obioberoi.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2015"}],"version-history":[{"count":33,"href":"https:\/\/obioberoi.com\/index.php?rest_route=\/wp\/v2\/posts\/2015\/revisions"}],"predecessor-version":[{"id":2057,"href":"https:\/\/obioberoi.com\/index.php?rest_route=\/wp\/v2\/posts\/2015\/revisions\/2057"}],"wp:attachment":[{"href":"https:\/\/obioberoi.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2015"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/obioberoi.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2015"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/obioberoi.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2015"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}