﻿
{"id":19562,"date":"2020-11-30T18:00:52","date_gmt":"2020-11-30T18:00:52","guid":{"rendered":"https:\/\/www.gencayyildiz.com\/blog\/?p=19562"},"modified":"2020-11-30T18:00:52","modified_gmt":"2020-11-30T18:00:52","slug":"entity-framework-core-keyless-entity-types","status":"publish","type":"post","link":"https:\/\/www.gencayyildiz.com\/blog\/entity-framework-core-keyless-entity-types\/","title":{"rendered":"Entity Framework Core &#8211; Keyless Entity Types"},"content":{"rendered":"<div id=\"fb-root\"><\/div>\n<p>Merhaba,<\/p>\n<p>Uygulamalarda kullan\u0131lan ORM&#8217;ler her ne kadar bizlerin yerine sorgu \u00fcretip, \u00e7al\u0131\u015ft\u0131rsa da bazen sunucu taraf\u0131nda haz\u0131r bir query bar\u0131nd\u0131ran view yahut stored procedure gibi yap\u0131lanmalardan gelen result&#8217;lar\u0131n da ORM vas\u0131tas\u0131yla Entity Type misali kullan\u0131lmas\u0131 ihtiya\u00e7 olabilmektedir. \u0130\u015fte bu durumda, Entity Framework Core 2.1 ile <em>Query Types<\/em> olarak hayat\u0131m\u0131za giren ve 3.1 s\u00fcr\u00fcm\u00fcnde <em>Keyless Entity Types<\/em> olarak tekrar isimlendirilen \u00f6zellik ile bu ihtiya\u00e7 desteklenmi\u015f ve rahat\u00e7a \u00e7\u00f6z\u00fclebilir hale getirilmi\u015ftir.<\/p>\n<blockquote><p><em style=\"color:orange;\">Keyless Entity Types; normal entity type&#8217;lara ek olarak, primary key i\u00e7ermeyen query&#8217;lere kar\u015f\u0131 veritaban\u0131 sorgular\u0131 y\u00fcr\u00fctmek i\u00e7in kullan\u0131labilmektedir.<\/em><\/p><\/blockquote>\n<p>Genellikle <code>group by<\/code>, <code>pivot<\/code> vs. gibi i\u015flemlerle yap\u0131lan istatistiksel \u00e7al\u0131\u015fmalar neticesinde \u00fcretilen veriler primary key bar\u0131nd\u0131rmayan sorgu sonu\u00e7lar\u0131 do\u011furmaktad\u0131rlar. Bizler bu tarz sorgular\u0131 <em>Keyless Entity Types<\/em> \u00f6zelli\u011fi ile sanki bir entity&#8217;e kar\u015f\u0131l\u0131k geliyormu\u015f gibi Entity Framework Core yap\u0131lanmas\u0131na dahil edebiliyor ve \u00e7al\u0131\u015fmalar\u0131m\u0131z\u0131 ger\u00e7ekle\u015ftirebiliyoruz.<\/p>\n<p>\u0130lgili \u00f6zelli\u011fi \u00f6rneklendirebilmek i\u00e7in direkt bir senaryo \u00fczerinden pratikle\u015ftirelim. \u015e\u00f6yle ki; &#8216;Employees&#8217; ve &#8216;Sales&#8217; olmak \u00fczere aralar\u0131nda bire \u00e7ok ili\u015fki olan iki adet tablo ve bir adet, sunucuda hangi employee&#8217;un ka\u00e7 adet sat\u0131\u015f yapt\u0131\u011f\u0131n\u0131 hesaplayan bir group by i\u015flemi yapan view tasarlayal\u0131m.<\/p>\n<p>Buyrun ba\u015flayal\u0131m&#8230;<\/p>\n<p>Entityler;<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public class Employee\r\n    {\r\n        public int Id { get; set; }\r\n        public string Name { get; set; }\r\n        public string Surname { get; set; }\r\n        public int Position { get; set; }\r\n        public ICollection&lt;Sale&gt; Sales { get; set; }\r\n    }\r\n<\/pre>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public class Sale\r\n    {\r\n        public int Id { get; set; }\r\n        public int EmployeeId { get; set; }\r\n        public string SaleExplanation { get; set; }\r\n        public Employee Employee { get; set; }\r\n    }\r\n<\/pre>\n<p>Context nesnesi;<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public class CompanyContext : DbContext\r\n    {\r\n        public DbSet&lt;Employee&gt; Employees { get; set; }\r\n        public DbSet&lt;Sale&gt; Sales { get; set; }\r\n\r\n        protected override void OnModelCreating(ModelBuilder modelBuilder)\r\n        {\r\n            modelBuilder.Entity&lt;Employee&gt;().HasData(\r\n                new Employee { Id = 1, Name = &quot;Hilmi&quot;, Surname = &quot;Celayir&quot; },\r\n                new Employee { Id = 2, Name = &quot;H\u00fcseyin&quot;, Surname = &quot;S\u00fcmer&quot; },\r\n                new Employee { Id = 3, Name = &quot;\u015euayip&quot;, Surname = &quot;Aldatmaz&quot; }\r\n                );\r\n            modelBuilder.Entity&lt;Sale&gt;().HasData(\r\n                new Sale { Id = 1, EmployeeId = 1 },\r\n                new Sale { Id = 2, EmployeeId = 2 },\r\n                new Sale { Id = 3, EmployeeId = 3 },\r\n                new Sale { Id = 4, EmployeeId = 1 },\r\n                new Sale { Id = 5, EmployeeId = 2 },\r\n                new Sale { Id = 6, EmployeeId = 3 },\r\n                new Sale { Id = 7, EmployeeId = 3 },\r\n                new Sale { Id = 8, EmployeeId = 3 },\r\n                new Sale { Id = 9, EmployeeId = 1 }\r\n                );\r\n\r\n            base.OnModelCreating(modelBuilder);\r\n        }\r\n        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)\r\n        {\r\n            optionsBuilder.UseSqlServer(&quot;Server=.;Database=CompanyDb;Trusted_Connection=True;&quot;);\r\n            base.OnConfiguring(optionsBuilder);\r\n        }\r\n    }\r\n<\/pre>\n<p>Bu tasar\u0131mlardan sonra Package Manager Console \u00fczerinden <code style=\"color:red;\">add-migration mig_1<\/code> talimat\u0131n\u0131 verelim ve olu\u015fturulan migration&#8217;\u0131n &#8216;Up&#8217; fonksiyonunun en son sat\u0131r\u0131na a\u015fa\u011f\u0131daki &#8216;View_EmployeeSales&#8217; isimli view&#8217;i olu\u015fturan kodlar\u0131 yerle\u015ftirelim.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nusing Microsoft.EntityFrameworkCore.Migrations;\r\n\r\nnamespace KeylessEntityTypes.Migrations\r\n{\r\n    public partial class mig_1 : Migration\r\n    {\r\n        protected override void Up(MigrationBuilder migrationBuilder)\r\n        {\r\n            .\r\n            .\r\n            .\r\n            migrationBuilder.Sql(@&quot;CREATE VIEW View_EmployeeSales\r\n                                   AS\r\n                                   SELECT e.Name, COUNT(*) &#x5B;Total Sales] FROM Employees e\r\n                                   JOIN Sales s\r\n                                   ON e.Id = s.EmployeeId\r\n                                   GROUP BY e.Name\r\n                                &quot;);\r\n        }\r\n    }\r\n}\r\n<\/pre>\n<p>Ve son olarak <code style=\"color:red;\">update-database<\/code> talimat\u0131yla tasarlanan yap\u0131y\u0131 migrate edelim.<\/p>\n<p>\u015eimdi olu\u015fturulan veritaban\u0131nda &#8216;View_EmployeeSales&#8217; view&#8217;ini sorgulayal\u0131m ve nas\u0131l bir sonu\u00e7 geldi\u011fini hep beraber g\u00f6zlemleyelim.<br \/>\n<a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/11\/Entity-Framework-Core-Keyless-Entity-Types.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/11\/Entity-Framework-Core-Keyless-Entity-Types.jpg\" alt=\"Entity Framework Core - Keyless Entity Types\" width=\"316\" height=\"146\" class=\"aligncenter size-full wp-image-19581\" srcset=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/11\/Entity-Framework-Core-Keyless-Entity-Types.jpg 316w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/11\/Entity-Framework-Core-Keyless-Entity-Types-300x139.jpg 300w\" sizes=\"auto, (max-width: 316px) 100vw, 316px\" \/><\/a><br \/>\nEvet&#8230; G\u00f6r\u00fcld\u00fc\u011f\u00fc \u00fczere bu sonucu Entity Framework Core ORM&#8217;sinin &#8216;Keyless Entity Types&#8217; \u00f6zelli\u011fi sayesinde bir entity ile e\u015fle\u015ftirecek ve daha rahat sorgulayabilece\u011fiz.<\/p>\n<p>Bunun i\u00e7in devam edelim&#8230;<\/p>\n<p>\u00d6ncelikle sorgu sonucuna uygun modelde bir entity tasarlayal\u0131m. Misal &#8216;EmployeeSale&#8217; isminde olabilir&#8230;<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public class EmployeeSale\r\n    {\r\n        public string Name { get; set; }\r\n        public int TotalSales { get; set; }\r\n    }\r\n<\/pre>\n<p>Ard\u0131ndan bu entity&#8217;i context nesnesine hem DbSet olarak ekleyelim hem de override edilen &#8216;OnModelCreating&#8217; metodu i\u00e7erisinde entity&#8217;e uygun a\u015fa\u011f\u0131daki konfig\u00fcrasyonlar\u0131 ger\u00e7ekle\u015ftirelim.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public class CompanyContext : DbContext\r\n    {\r\n        public DbSet&lt;Employee&gt; Employees { get; set; }\r\n        public DbSet&lt;Sale&gt; Sales { get; set; }\r\n        public DbSet&lt;EmployeeSale&gt; EmployeeSales { get; set; }\r\n        protected override void OnModelCreating(ModelBuilder modelBuilder)\r\n        {\r\n            modelBuilder.Entity&lt;EmployeeSale&gt;(es =&gt;\r\n                es.HasNoKey()\r\n                  .ToView(&quot;View_EmployeeSales&quot;)\r\n                  .Property(p =&gt; p.TotalSales).HasColumnName(&quot;Total Sales&quot;));\r\n            .\r\n            .\r\n            .\r\n<\/pre>\n<p>Yukar\u0131daki kod blo\u011funu incelerseniz e\u011fer, <em><strong>5.<\/strong><\/em> sat\u0131rda ilgili entity DbSet olarak eklenmekte ve <em><strong>8.<\/strong><\/em> sat\u0131rda ise eklenen entity&#8217;nin konfig\u00fcrasyonlar\u0131 ger\u00e7ekle\u015ftirilmektedir. <em><strong>9.<\/strong><\/em> sat\u0131rda &#8216;HasNoKey&#8217; fonksiyonu ile ilgili entity&#8217;nin bir primary key&#8217;i olmad\u0131\u011f\u0131n\u0131, <em><strong>10.<\/strong><\/em> sat\u0131rda sunucudaki &#8216;View_EmployeeSales&#8217; isimli view&#8217;e kar\u015f\u0131l\u0131k geldi\u011fini ve <em><strong>11.<\/strong><\/em> sat\u0131rda ise &#8216;Total Sales&#8217; olarak gelen kolonun &#8216;TotalSales&#8217; propertysi ile e\u015fle\u015fmesi gerekti\u011fini ifade etmekteyiz.<\/p>\n<p>Sonu\u00e7 olarak yap\u0131lan bu in\u015fa neticesinde ilgili DbSet&#8217;i sorgularsak e\u011fer;<br \/>\n<a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/11\/Entity-Framework-Core-Keyless-Entity-Types-1.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/11\/Entity-Framework-Core-Keyless-Entity-Types-1.jpg\" alt=\"Entity Framework Core - Keyless Entity Types\" width=\"622\" height=\"306\" class=\"aligncenter size-full wp-image-19589\" srcset=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/11\/Entity-Framework-Core-Keyless-Entity-Types-1.jpg 622w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/11\/Entity-Framework-Core-Keyless-Entity-Types-1-300x148.jpg 300w\" sizes=\"auto, (max-width: 622px) 100vw, 622px\" \/><\/a><br \/>\n\u015feklinde sonu\u00e7lar\u0131 ba\u015far\u0131yla alabilmekteyiz.<\/p>\n<p>Ayr\u0131ca burada primary key olmayan veri illa ki bir view&#8217;den de\u011fil, LINQ sorgusundan da geliyor olabilir&#8230; Evet, yanl\u0131\u015f okumad\u0131n\u0131z \ud83d\ude42 Keyless Entity Types \u00f6zelli\u011fini kullanabilmek i\u00e7in arkada \u00e7al\u0131\u015facak olan query bir view olaca\u011f\u0131 gibi bir LINQ sorgusuda olabilir.<\/p>\n<p>Bunun i\u00e7in &#8216;OnModelCreating&#8217; metodunda yap\u0131lan konfig\u00fcrasyonun a\u015fa\u011f\u0131daki gibi de\u011fi\u015ftirilmesi yeterli olacakt\u0131r.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n            modelBuilder.Entity&lt;EmployeeSale&gt;(es =&gt;\r\n                es.HasNoKey()\r\n                  .ToQuery(() =&gt; Sales.GroupBy(s =&gt; s.Employee.Name)\r\n                                      .Select(es =&gt; new EmployeeSale\r\n                                      {\r\n                                          Name = es.Key,\r\n                                          TotalSales = es.Count()\r\n                                      })));\r\n<\/pre>\n<p>G\u00f6r\u00fcld\u00fc\u011f\u00fc \u00fczere &#8216;ToQuery&#8217; fonksiyonu sayesinde herhangi bir view&#8217;e ba\u011f\u0131ml\u0131l\u0131k olmaks\u0131z\u0131n LINQ ile sorgu olu\u015fturulabilmektedir.<\/p>\n<h5 style=\"color:#e83e8c;\">[Keyless] Attribute&#8217;u<\/h5>\n<p>Primary key&#8217;i olmayan entity&#8217;ler de &#8216;OnModelCreating&#8217; \u00fczerinden &#8216;HasNoKey&#8217; fonksiyonu ile bildirim yap\u0131lmas\u0131na alternatif olarak &#8216;Keyless&#8217; attribute&#8217;u \u00fcretilmi\u015ftir. Bu attribute sayesinde primary key&#8217;i olmayan entity direkt i\u015faretlenerek bildiride bulunulabilmektedir.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    &#x5B;Keyless]\r\n    public class EmployeeSale\r\n    {\r\n        public string Name { get; set; }\r\n        public int TotalSales { get; set; }\r\n    }\r\n<\/pre>\n<p>\u0130lgilenenlerin faydalanmas\u0131 dile\u011fiyle&#8230;<br \/>\nSonraki yaz\u0131lar\u0131mda g\u00f6r\u00fc\u015fmek \u00fczere&#8230;<br \/>\n\u0130yi \u00e7al\u0131\u015fmalar&#8230;<\/p>\n<!-- AddThis Advanced Settings generic via filter on the_content --><!-- AddThis Share Buttons generic via filter on the_content -->","protected":false},"excerpt":{"rendered":"<p>Merhaba, Uygulamalarda kullan\u0131lan ORM&#8217;ler her ne kadar bizlerin yerine sorgu \u00fcretip, \u00e7al\u0131\u015ft\u0131rsa da bazen sunucu taraf\u0131nda haz\u0131r bir query bar\u0131nd\u0131ran view yahut stored procedure gibi yap\u0131lanmalardan gelen result&#8217;lar\u0131n da ORM vas\u0131tas\u0131yla Entity Type misali&#46;&#46;&#46;<!-- 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":1,"featured_media":11538,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[955,2914],"tags":[3982,3981,2850,3980,3978,3977,3979],"class_list":["post-19562","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-entity-framework","category-entity-framework-core","tag-ef-core-keyless","tag-ef-core-keyless-attribute","tag-entity-framework-core","tag-keyless-attribute","tag-keyless-entity-types","tag-query-types","tag-query-types-keyless-entity-types"],"amp_enabled":true,"_links":{"self":[{"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/posts\/19562","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/comments?post=19562"}],"version-history":[{"count":34,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/posts\/19562\/revisions"}],"predecessor-version":[{"id":19600,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/posts\/19562\/revisions\/19600"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/media\/11538"}],"wp:attachment":[{"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/media?parent=19562"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/categories?post=19562"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/tags?post=19562"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}