﻿
{"id":24873,"date":"2022-04-22T01:32:03","date_gmt":"2022-04-22T01:32:03","guid":{"rendered":"https:\/\/www.gencayyildiz.com\/blog\/?p=24873"},"modified":"2022-04-22T01:32:03","modified_gmt":"2022-04-22T01:32:03","slug":"query-object-design-patternsorgu-nesnesi-tasarim-deseni","status":"publish","type":"post","link":"https:\/\/www.gencayyildiz.com\/blog\/query-object-design-patternsorgu-nesnesi-tasarim-deseni\/","title":{"rendered":"Query Object Design Pattern(Sorgu Nesnesi Tasar\u0131m Deseni)"},"content":{"rendered":"<div id=\"fb-root\"><\/div>\n<p>Merhaba,<\/p>\n<p>G\u00fcn\u00fcm\u00fczde bir\u00e7ok uygulamada veritaban\u0131 i\u015flemleri i\u00e7in yayg\u0131n olarak ORM(Object Relational Mapping) yakla\u015f\u0131m\u0131 tercih ediliyor olsa da bir\u00e7ok k\u00fc\u00e7\u00fck ve orta \u00f6l\u00e7ekli \u015firket taraf\u0131ndan ve hatta geleneksel olarak radikal de\u011fi\u015fiklikleri kald\u0131ramayacak kadar k\u00f6kl\u00fc framework&#8217;lere sahip olan b\u00fcy\u00fck \u015firketler taraf\u0131ndan da Ado.NET&#8217;e dayal\u0131 olarak uygulama geli\u015ftirildi\u011fine de \u015fahit olabilmekteyiz. Tecr\u00fcbeyle sabittir ki, Ado.NET ile ger\u00e7ekle\u015ftirilen veritaban\u0131 \u00e7al\u0131\u015fmalar\u0131, s\u00fcrekli de\u011fi\u015fiklik g\u00f6steren proje ihtiya\u00e7lar\u0131 neticesinde ka\u00e7\u0131n\u0131lmaz olarak karma\u015f\u0131k hale gelebilmekte ve bu karma\u015f\u0131kl\u0131\u011f\u0131 y\u00f6netmek ve hatta de\u011fi\u015fiklikler i\u00e7in programc\u0131n\u0131n dikkat becerisine g\u00fcvenmek gerekmektedir. Halbuki bu karma\u015f\u0131kl\u0131\u011f\u0131 m\u00fcmk\u00fcn mertebe ORM gibi dinamik bir \u00e7\u00f6z\u00fcmle y\u00f6netebilmek ve olu\u015fturulacak sorgular\u0131 programc\u0131n\u0131n dikkatinden soyutlayabilmek s\u00fcre\u00e7 a\u00e7\u0131s\u0131ndan \u00e7\u00f6z\u00fcmlerin en idealidir kanaatindeyiz. \u0130\u015fte b\u00f6yle bir durumda veritaban\u0131 sorgular\u0131n\u0131n bir nesne \u00fczerinden temsil edilerek geli\u015ftiriciden ba\u011f\u0131ms\u0131z bir \u015fekilde y\u00f6netilebilmesini sa\u011flayan <em>Query Object Tasar\u0131m Deseni<\/em>ni kullanabilir ve ideal \u00e7\u00f6z\u00fcme bir ad\u0131m daha yak\u0131nla\u015farak \u00e7al\u0131\u015fmalar\u0131m\u0131za devam edebiliriz.<\/p>\n<h3>Neden Query Object Design Pattern&#8217;\u0131 Kullanmal\u0131y\u0131z?<\/h3>\n<p>Yukar\u0131da giri\u015f paragraf\u0131nda bahsedildi\u011fi \u00fczere uygulama i\u00e7erisinde ORM kullan\u0131lm\u0131yorsa ve kod i\u00e7erisinde SQL sorgular\u0131 olu\u015fturulacaksa Query Object Design Pattern ideal bir \u00e7\u00f6z\u00fcm sa\u011flamaktad\u0131r. \u00c7\u00fcnk\u00fc, geli\u015ftiriciler kullan\u0131lacak veritaban\u0131na ve o veritaban\u0131n\u0131n sorgulama diline tam hakim olamayabilirler. Yahut veritaban\u0131na hakim olsalar bile uygulaman\u0131n veritaban\u0131 \u015femas\u0131n\u0131\/mant\u0131\u011f\u0131n\u0131 bilmeleri\/\u00e7\u00f6zmeleri gerekmektedir. Hangi tabloda hangi verilerin tutuldu\u011fu, uygulama konfig\u00fcrasyonlar\u0131n\u0131n nerede tan\u0131mland\u0131\u011f\u0131 veya tablolar aras\u0131 ili\u015fkilerin nas\u0131l olmas\u0131 gerekti\u011fi vs. gibi bir\u00e7ok durum geli\u015ftiricileri ilgilendirecektir. Oysa bir geli\u015ftiricinin i\u015fi m\u00fcmk\u00fcn mertebe elindeki malzemelerle ortaya i\u015f koyabilmek ve bunu yay\u0131na s\u00fcrebilmektir. Bu kadar bilgiyi \u00f6\u011frenmek i\u00e7in verece\u011fi vakit \u015firket i\u00e7in olduk\u00e7a maliyetli bir netice ortaya koyabilir. \u0130\u015fte, Quert Object tasar\u0131m deseni bu ve bunlara benzer durumlar\u0131n minimum bilgi gereksinimi ile \u00e7\u00f6z\u00fclmesini sa\u011flayacak ve geli\u015ftiricinin direkt olarak i\u015fe odaklanmas\u0131n\u0131 sa\u011flayacakt\u0131r.<\/p>\n<blockquote><p><em style=\"color:green;\">Quert Object, bir veritaban\u0131 sorgusunu temsil eden nesne olarak anla\u015f\u0131labilir.<\/em><\/p><\/blockquote>\n<p>Quert Object tasar\u0131m deseni sayesinde nesne olarak geli\u015ftirilen sorgular ihtiya\u00e7 dahilinde kullan\u0131ld\u0131ktan sonra tekrar ihtiyaca binaen depolanabilmektedir. Yap\u0131n\u0131n g\u00fczel yanlar\u0131ndan biriside buras\u0131d\u0131r. Ayr\u0131ca bu modellemenin ana yararlar\u0131ndan birisinin uygulamay\u0131 veritaban\u0131 sorgu dilinden tamamen soyutlamas\u0131d\u0131r diyebiliriz. Bunu yaz\u0131m\u0131z\u0131n devam\u0131nda daha net bir \u015fekilde inceliyor olaca\u011f\u0131z.<\/p>\n<h5>Query Object Design Pattern Diyagram\u0131n\u0131 \u0130nceleyelim<\/h5>\n<p><a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/04\/Query-Object-Design-PatternSorgu-Nesnesi-Tasarim-Deseni.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/04\/Query-Object-Design-PatternSorgu-Nesnesi-Tasarim-Deseni.png\" alt=\"Query Object Design Pattern(Sorgu Nesnesi Tasar\u0131m Deseni)\" width=\"441\" height=\"301\" class=\"aligncenter size-full wp-image-24883\" srcset=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/04\/Query-Object-Design-PatternSorgu-Nesnesi-Tasarim-Deseni.png 441w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/04\/Query-Object-Design-PatternSorgu-Nesnesi-Tasarim-Deseni-300x205.png 300w\" sizes=\"auto, (max-width: 441px) 100vw, 441px\" \/><\/a>Yukar\u0131daki diyagram \u015femas\u0131na g\u00f6z atarsan\u0131z e\u011fer ihtiya\u00e7 duyulan SQL sorgusunu ve o sorguda kullan\u0131lacak kriterleri temsil eden nesnelerin kullan\u0131ld\u0131\u011f\u0131 bir tasar\u0131m g\u00f6rmekteyiz. Modelleme, tasar\u0131m a\u00e7\u0131s\u0131ndan bu kadar basittir.<\/p>\n<p>Bu tasar\u0131m neticesinde olu\u015fturulan Query Object pattern sayesinde, nesnelerin yorumlanarak SQL \u00e7\u0131kt\u0131s\u0131 olu\u015fturan bir model ortaya koyulmaktad\u0131r. E\u011fer ki burada nesne yerine bir veriyi yorumlayarak ba\u015fka bir \u00e7\u0131kt\u0131 olu\u015fturuyor olsayd\u0131k bu Interpreter tasar\u0131m deseni olacakt\u0131. <em><u>Bu benzerlikten dolay\u0131 kimi programc\u0131lar, Query Object pattern&#8217;\u0131n ger\u00e7ek bir tasar\u0131m deseni olmad\u0131\u011f\u0131, Interpreter pattern&#8217;\u0131n sadece farkl\u0131 bir modellemesi oldu\u011fu yorumunda bulunmaktad\u0131rlar.<\/u><\/em> Do\u011frusu bu yorumda hakl\u0131l\u0131k paylar\u0131 yokta de\u011fildir! \u00c7\u00fcnk\u00fc Query Object tasar\u0131m deseni sayesinde verilere g\u00f6re de uygun yorumlamalar yaparak \u00e7e\u015fitli SQL \u00e7\u0131kt\u0131lar\u0131 da sunulabilmektedir.<\/p>\n<blockquote><p><em>Quert Object, bir yorumlay\u0131c\u0131d\u0131r, yani kendisini bir SQL sorgusuna d\u00f6n\u00fc\u015ft\u00fcrebilen bir nesne yap\u0131s\u0131d\u0131r.<\/p>\n<div style=\"text-align:right;\">\nMartin Fowler\n<\/div>\n<p><\/em>\n<\/p><\/blockquote>\n<p>Query Object nesneleri tasarlan\u0131rken esnek yap\u0131lar kurar ve b\u00f6ylece veritaban\u0131 sistemlerinin her \u00f6zelliklerini kullan\u0131labilir hale getiririz. B\u00f6ylece efektif kullan\u0131m sa\u011flayabilir ve sorgulardaki komplekslik oran\u0131n\u0131 artt\u0131rabiliriz. Ayr\u0131ca, Query Object&#8217;ler ile olu\u015fturulacak SQL \u00e7\u0131kt\u0131lar\u0131n\u0131, \u00e7al\u0131\u015f\u0131lacak veritaban\u0131 sistemine g\u00f6re farkl\u0131 \u015fekilde elde edebiliriz. Bu farkl\u0131l\u0131klar sayesinde birden fazla veritaban\u0131 sistemi ile \u00e7al\u0131\u015fabiliriz.<\/p>\n<p>\u00d6zellikle karma\u015f\u0131k sorgulama s\u00fcre\u00e7lerinde bu pattern sayesinde olduk\u00e7a performansl\u0131 bir \u00e7al\u0131\u015fma sergilenmi\u015f olacakt\u0131r. Nihayetinde koda g\u00f6m\u00fcl\u00fc kompleks bir sorgunun s\u00fcre\u00e7teki ihtiya\u00e7lara istinaden modifiye edilmesi ve bak\u0131m\u0131 olduk\u00e7a maliyetli olacakt\u0131r. Lakin ihtiya\u00e7 do\u011frultusunda olas\u0131 de\u011fi\u015fiklikleri en ba\u015fta \u00f6ng\u00f6rerek bu tasar\u0131m\u0131n temellerinin at\u0131lmas\u0131 b\u00fcy\u00fck avantaj sa\u011flayacakt\u0131r.<\/p>\n<h3>Ne Zaman Kullan\u0131lmaz!<\/h3>\n<p>Bir olgunun art\u0131s\u0131 oldu\u011fu kadar eksisi de olabilmektedir. Dolay\u0131s\u0131yla Query Object nesnelerinin getirisi kadar g\u00f6t\u00fcr\u00fcs\u00fc de mevcuttur. Buradaki g\u00f6t\u00fcr\u00fc ilgili nesnelerin olu\u015fturulma maliyeti, bir ba\u015fka deyi\u015fle zahmetidir. Evet, bir Query Object olu\u015fturmak\/tasarlamak olduk\u00e7a zahmetlidir. Bundan dolay\u0131; e\u011fer ki \u00e7al\u0131\u015f\u0131lan projede herhangi bir ORM teknolojisi kullan\u0131l\u0131yorsa bu pattern&#8217;\u0131n uygulanmas\u0131 kesinlikle tavsiye edilmemektedir. Ha nerede ve ne zaman kullan\u0131laca\u011f\u0131n\u0131 soruyorsan\u0131z e\u011fer bu sorunun cevab\u0131n\u0131 yukar\u0131daki sat\u0131rlarda verdi\u011fim kanaatindeyim \ud83d\ude42<\/p>\n<h3>Avantajlar\u0131<\/h3>\n<ul>\n<li>\u0130htiya\u00e7 duyulan SQL sorgusunu parametreli fonksiyonaliteler e\u015fli\u011finde bar\u0131nd\u0131r\u0131r. B\u00f6ylece gelen parametrelere g\u00f6re dinamik olarak SQL&#8217;i olu\u015fturabilir.<\/li>\n<li>Veritaban\u0131 sorgu dilini geli\u015ftiriciden tamamen soyutlar, ba\u011f\u0131ms\u0131z hale getirir.<\/li>\n<li>Bir\u00e7ok veritaban\u0131n\u0131 desteklemektedir.<\/li>\n<\/ul>\n<h3>\u00d6rnek Tasar\u0131m Modellemesi &#038; Kullan\u0131m<\/h3>\n<p>Bu pattern&#8217;\u0131 net bir \u015fekilde \u00f6rneklendirebilmek i\u00e7in \u00f6ncelikle bir developer&#8217;\u0131n Ado.NET ile koda g\u00f6m\u00fcl\u00fc sorgularla \u00e7al\u0131\u015f\u0131rken ne gibi bir atmosferde oldu\u011funu sim\u00fcle ederek bu yakla\u015f\u0131m\u0131n gereklili\u011fini ortaya koymaya \u00e7al\u0131\u015fal\u0131m. Bunun i\u00e7in a\u015fa\u011f\u0131daki gibi tasarlanarak Ado.NET temelleri at\u0131lan bir s\u0131n\u0131f \u00fczerinden ihtiya\u00e7lar\u0131n giderildi\u011fini varsayarak ba\u015flayal\u0131m:<\/p>\n<div style=\"font-size:12px;\">\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public class DALContext\r\n    {\r\n        readonly static SqlConnection _connection;\r\n        readonly static object _object = new();\r\n        static DALContext()\r\n        {\r\n            lock (_object)\r\n                _connection = new(&quot;Server=localhost, 1433;Database=QueryObjectDesignPatternDB;User ID=SA;Password=***&quot;);\r\n        }\r\n        async Task&lt;SqlConnection&gt; GetOpenConnectionAsync()\r\n        {\r\n            if (_connection.State == ConnectionState.Closed)\r\n                await _connection.OpenAsync();\r\n\r\n            return _connection;\r\n        }\r\n        public async Task CloseConnectionAsync()\r\n        {\r\n            if (_connection.State == ConnectionState.Open)\r\n                await _connection.CloseAsync();\r\n        }\r\n        public async Task&lt;SqlDataReader&gt; ExecuteQueryAsync(string query)\r\n        {\r\n            using SqlCommand command = new(query, await GetOpenConnectionAsync());\r\n            SqlDataReader dr = await command.ExecuteReaderAsync();\r\n            return dr;\r\n        }\r\n    }\r\n<\/pre>\n<\/div>\n<p>G\u00f6r\u00fcld\u00fc\u011f\u00fc \u00fczere Ado.NET mimarisi e\u015fli\u011finde veritaban\u0131n\u0131 sorgulamam\u0131z\u0131 sa\u011flayacak olan temel i\u015flemlerin icra edildi\u011fi &#8216;DALContext&#8217; isimli bir s\u0131n\u0131f\u0131m\u0131z mevcuttur. Bu s\u0131n\u0131f\u0131 kullanarak a\u015fa\u011f\u0131daki gibi veritaban\u0131ndaki &#8216;Products&#8217; tablosuna sorgular g\u00f6nderilebildi\u011fini varsayal\u0131m.<div id=\"attachment_24906\" style=\"width: 279px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/04\/Query-Object-Design-PatternSorgu-Nesnesi-Tasarim-Deseni-1.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-24906\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/04\/Query-Object-Design-PatternSorgu-Nesnesi-Tasarim-Deseni-1.png\" alt=\"Query Object Design Pattern(Sorgu Nesnesi Tasar\u0131m Deseni)\" width=\"269\" height=\"238\" class=\"size-full wp-image-24906\" \/><\/a><p id=\"caption-attachment-24906\" class=\"wp-caption-text\"><span style=\"font-size:12px;\"><em>&#8216;Products&#8217; tablosu&#8230;<\/em><\/span><\/p><\/div><\/p>\n<div style=\"font-size:12px;\">\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nDALContext context = new();\r\nSqlDataReader dr = await context.ExecuteQueryAsync(&quot;SELECT * FROM Products&quot;);\r\nwhile (await dr.ReadAsync())\r\n    Console.WriteLine($&quot;Id : {dr&#x5B;&quot;Id&quot;]}\\tName : {dr&#x5B;&quot;Name&quot;]}\\tStock : {dr&#x5B;&quot;Stock&quot;]}\\tPrice : {dr&#x5B;&quot;Price&quot;]}&quot;);\r\nawait context.CloseConnectionAsync();\r\n<\/pre>\n<\/div>\n<p>Yukar\u0131daki kodu derleyip \u00e7al\u0131\u015ft\u0131rd\u0131\u011f\u0131m\u0131zda a\u015fa\u011f\u0131daki gibi veritaban\u0131ndan istenilen verilerin elde edildi\u011fini g\u00f6r\u00fcyor olaca\u011f\u0131z.<a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/04\/Query-Object-Design-PatternSorgu-Nesnesi-Tasarim-Deseni-2.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/04\/Query-Object-Design-PatternSorgu-Nesnesi-Tasarim-Deseni-2.png\" alt=\"Query Object Design Pattern(Sorgu Nesnesi Tasar\u0131m Deseni)\" width=\"430\" height=\"65\" class=\"aligncenter size-full wp-image-24908\" srcset=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/04\/Query-Object-Design-PatternSorgu-Nesnesi-Tasarim-Deseni-2.png 430w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/04\/Query-Object-Design-PatternSorgu-Nesnesi-Tasarim-Deseni-2-300x45.png 300w\" sizes=\"auto, (max-width: 430px) 100vw, 430px\" \/><\/a>\u015eimdi bir developer bu ve benzeri bir sorguyu yazarken insani halden \u00f6t\u00fcr\u00fc a\u015fa\u011f\u0131daki gibi hata(lar) yapma ihtimali olas\u0131 m\u0131d\u0131r?<br \/>\n<code style=\"font-size:15px;color:red;\"><strong>SELECT *<del>,<\/del> FROM Products<\/strong><\/code><br \/>\n<code style=\"font-size:15px;color:red;\"><strong>SELECT Name, <del>Fiyat<\/del> FROM Products<\/strong><\/code><br \/>\n<code style=\"font-size:15px;color:red;\"><strong>SELECT Name, <del>Fiyat<\/del> FROM <del>Urunler<\/del><\/strong><\/code><br \/>\nTabi ki de olas\u0131d\u0131r \ud83d\ude42 Bu hatalar\u0131n olas\u0131 olmalar\u0131n\u0131n nedenleri \u00fcst paragraflarda da bahsedildi\u011fi gibi k\u00e2h developer&#8217;\u0131n anl\u0131k bilinciyle ilgili dikkat da\u011f\u0131n\u0131kl\u0131\u011f\u0131 k\u00e2h ilgili veritaban\u0131 diline hakim olamamas\u0131 gibi t\u00fcrl\u00fc sebepler olabilir. <em>Peki, sorgular\u0131m\u0131z bu kadar m\u0131?<\/em> Tabi ki de hay\u0131r! Temel d\u00fczeyde bir uygulamada bile gelecek verilerin filtrelendi\u011fi \u015fartl\u0131 sorgular ya da farkl\u0131 tablolar\u0131n birle\u015ftirildi\u011fi join&#8217;li sorgular ka\u00e7\u0131n\u0131lmaz olarak kullan\u0131lmaktad\u0131r. Dolay\u0131s\u0131yla bu tarz sorgular\u0131 developer&#8217;\u0131n sorumlulu\u011funa b\u0131rak\u0131rsak komplekslik artt\u0131k\u00e7a olas\u0131 hata oranlar\u0131 da muhtemeldir ki artacakt\u0131r.<\/p>\n<p>\u0130\u015fte b\u00f6yle bir durumda sorgular\u0131 developer odakl\u0131 hatalardan ar\u0131nd\u0131rabilmek i\u00e7in olu\u015fturulma sorumluluklar\u0131n\u0131 developerlardan soyutlayarak otomatize hale getirebilmek i\u00e7in Query Object pattern&#8217;\u0131n\u0131 uygulamam\u0131z gerekmektedir. \u015eimdi gelin ad\u0131m ad\u0131m bu pattern&#8217;\u0131n uygulanmas\u0131n\u0131 inceleyelim.<\/p>\n<ul>\n<li><strong><em>Ad\u0131m 1<\/em><\/strong><br \/>\n\u0130lk olarak bir sorgudaki kriterleri\/\u015fartlar\u0131(where) tarif edecek olan s\u0131n\u0131f\u0131 in\u015fa edelim.<\/p>\n<div style=\"font-size:12px;\">\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public class Criteria&lt;TModel&gt;\r\n    {\r\n        string @operator;\r\n        string field;\r\n        object value;\r\n        QueryLogicalOperator queryOperator;\r\n\r\n        public QueryLogicalOperator QueryOperator =&gt; queryOperator;\r\n\r\n        public Criteria(string @operator, string field, object value, QueryLogicalOperator queryOperator = QueryLogicalOperator.None)\r\n        {\r\n            this.@operator = @operator;\r\n            this.field = field;\r\n            this.value = value;\r\n            this.queryOperator = queryOperator;\r\n        }\r\n\r\n        static string DebugField&lt;TKey&gt;(Expression&lt;Func&lt;TModel, TKey&gt;&gt; method)\r\n        {\r\n            string field = method.Body.ToString();\r\n            field = field.Remove(0, field.IndexOf(&quot;.&quot;) + 1);\r\n            return field;\r\n        }\r\n\r\n        public static Criteria&lt;TModel&gt; GreaterThan(string field, object value, QueryLogicalOperator queryOperator = QueryLogicalOperator.None)\r\n            =&gt; new(&quot;&gt;&quot;, field, value, queryOperator);\r\n        public static Criteria&lt;TModel&gt; GreaterThan&lt;TKey&gt;(Expression&lt;Func&lt;TModel, TKey&gt;&gt; method, object value, QueryLogicalOperator queryOperator = QueryLogicalOperator.None)\r\n        {\r\n            string field = DebugField(method);\r\n            return new(&quot;&gt;&quot;, field, value, queryOperator);\r\n        }\r\n\r\n        public static Criteria&lt;TModel&gt; GreaterThanOrEqual(string field, object value, QueryLogicalOperator queryOperator = QueryLogicalOperator.None)\r\n            =&gt; new(&quot;&gt;=&quot;, field, value, queryOperator);\r\n        public static Criteria&lt;TModel&gt; GreaterThanOrEqual&lt;TKey&gt;(Expression&lt;Func&lt;TModel, TKey&gt;&gt; method, object value, QueryLogicalOperator queryOperator = QueryLogicalOperator.None)\r\n        {\r\n            string field = DebugField(method);\r\n            return new(&quot;&gt;=&quot;, field, value, queryOperator);\r\n        }\r\n\r\n        public static Criteria&lt;TModel&gt; LessThan(string field, object value, QueryLogicalOperator queryOperator = QueryLogicalOperator.None)\r\n            =&gt; new(&quot;&lt;&quot;, field, value, queryOperator);\r\n        public static Criteria&lt;TModel&gt; LessThan&lt;TKey&gt;(Expression&lt;Func&lt;TModel, TKey&gt;&gt; method, object value, QueryLogicalOperator queryOperator = QueryLogicalOperator.None)\r\n        {\r\n            string field = DebugField(method);\r\n            return new(&quot;&lt;&quot;, field, value, queryOperator);\r\n        }\r\n\r\n        public static Criteria&lt;TModel&gt; LessThanOrEqual(string field, object value, QueryLogicalOperator queryOperator = QueryLogicalOperator.None)\r\n            =&gt; new(&quot;&lt;=&quot;, field, value, queryOperator);\r\n        public static Criteria&lt;TModel&gt; LessThanOrEqual&lt;TKey&gt;(Expression&lt;Func&lt;TModel, TKey&gt;&gt; method, object value, QueryLogicalOperator queryOperator = QueryLogicalOperator.None)\r\n        {\r\n            string field = DebugField(method);\r\n            return new(&quot;&lt;=&quot;, field, value, queryOperator);\r\n        }\r\n\r\n        public static Criteria&lt;TModel&gt; Equal(string field, object value, QueryLogicalOperator queryOperator = QueryLogicalOperator.None)\r\n            =&gt; new(&quot;=&quot;, field, value, queryOperator);\r\n        public static Criteria&lt;TModel&gt; Equal&lt;TKey&gt;(Expression&lt;Func&lt;TModel, TKey&gt;&gt; method, object value, QueryLogicalOperator queryOperator = QueryLogicalOperator.None)\r\n        {\r\n            string field = DebugField(method);\r\n            return new(&quot;=&quot;, field, value, queryOperator);\r\n        }\r\n\r\n        public static Criteria&lt;TModel&gt; Contains(string field, object value, QueryLogicalOperator queryOperator = QueryLogicalOperator.None)\r\n            =&gt; new(&quot;Like&quot;, field, $&quot;%{value}%&quot;, queryOperator);\r\n        public static Criteria&lt;TModel&gt; Contains&lt;TKey&gt;(Expression&lt;Func&lt;TModel, TKey&gt;&gt; method, object value, QueryLogicalOperator queryOperator = QueryLogicalOperator.None)\r\n        {\r\n            string field = DebugField(method);\r\n            return new(&quot;Like&quot;, field, $&quot;%{value}%&quot;, queryOperator);\r\n        }\r\n\r\n        public static Criteria&lt;TModel&gt; StartsWith(string field, object value, QueryLogicalOperator queryOperator = QueryLogicalOperator.None)\r\n            =&gt; new(&quot;Like&quot;, field, $&quot;{value}%&quot;, queryOperator);\r\n        public static Criteria&lt;TModel&gt; StartsWith&lt;TKey&gt;(Expression&lt;Func&lt;TModel, TKey&gt;&gt; method, object value, QueryLogicalOperator queryOperator = QueryLogicalOperator.None)\r\n        {\r\n            string field = DebugField(method);\r\n            return new(&quot;Like&quot;, field, $&quot;{value}%&quot;, queryOperator);\r\n        }\r\n\r\n        public static Criteria&lt;TModel&gt; EndsWith(string field, object value, QueryLogicalOperator queryOperator = QueryLogicalOperator.None)\r\n            =&gt; new(&quot;Like&quot;, field, $&quot;%{value}&quot;, queryOperator);\r\n        public static Criteria&lt;TModel&gt; EndsWith&lt;TKey&gt;(Expression&lt;Func&lt;TModel, TKey&gt;&gt; method, object value, QueryLogicalOperator queryOperator = QueryLogicalOperator.None)\r\n        {\r\n            string field = method.Body.ToString();\r\n            return new(&quot;Like&quot;, field, $&quot;%{value}&quot;, queryOperator);\r\n        }\r\n\r\n        public string GenerateSql()\r\n            =&gt; $&quot;{field} {@operator} {(value is int or long or float or decimal ? value : $&quot;'{value}'&quot;)}&quot;;\r\n    }\r\n<\/pre>\n<\/div>\n<p>Yukar\u0131daki kod blo\u011funu iyice analiz edersek e\u011fer; <strong><em>3<\/em><\/strong> ile <strong><em>6.<\/em><\/strong> sat\u0131r aral\u0131\u011f\u0131nda bir sorguda bulunacak kriterlerin temel par\u00e7alar\u0131n\u0131 tutacak field&#8217;lar olu\u015fturulmu\u015ftur. &#8216;@operator&#8217;, kriterin i\u015flevsel(b\u00fcy\u00fck, k\u00fc\u00e7\u00fck vs. gibi) operat\u00f6r\u00fcn\u00fc ifade ederken, &#8216;queryOperator&#8217; birden fazla kriter aras\u0131ndaki ve\/veya mant\u0131\u011f\u0131ndaki operat\u00f6r\u00fc ifade eder. &#8216;field&#8217; sorguda hangi kolona kriter uyguland\u0131\u011f\u0131n\u0131 ifade ederken, kriterin de\u011ferini de &#8216;value&#8217; ifade etmektedir.<\/p>\n<p><strong><em>8.<\/em><\/strong> sat\u0131rdaki &#8216;QueryOperator&#8217; property&#8217;si ise bir sonraki ad\u0131mda olu\u015fturaca\u011f\u0131m\u0131z ve bu &#8216;Criteria&lt;T&gt;&#8217; s\u0131n\u0131f\u0131n\u0131 kullanaca\u011f\u0131m\u0131z &#8216;Query&#8217; s\u0131n\u0131f\u0131 taraf\u0131ndan sorguya kriterleri hangi mant\u0131kta ekleyece\u011fimizi \u00f6\u011frenmemizi sa\u011flayacak olan property&#8217;dir.<\/p>\n<p><strong><em>25<\/em><\/strong> ile <strong><em>31.<\/em><\/strong> sat\u0131r aral\u0131\u011f\u0131ndaki static olarak tan\u0131mlanm\u0131\u015f &#8216;GreaterThan&#8217; isimli metot overload&#8217;lar\u0131 olu\u015fturulacak sorguya &#8216;b\u00fcy\u00fckt\u00fcr&#8217; mahiyetinde bir \u015fart eklemektedirler. Overload&#8217;lara bakarsan\u0131z e\u011fer biri manuel olarak parametrelerden &#8216;field&#8217; ve &#8216;value&#8217; de\u011ferlerini al\u0131rken di\u011feri ise &#8216;Func&lt;T&gt;&#8217; arac\u0131l\u0131\u011f\u0131yla bu i\u015flemi ger\u00e7ekle\u015ftirmektedir. Benzer mant\u0131kla; <strong><em>33<\/em><\/strong> &#8211; <strong><em>39<\/em><\/strong> sat\u0131r aral\u0131\u011f\u0131ndaki metotlar &#8216;b\u00fcy\u00fck e\u015fittir&#8217;, <strong><em>41<\/em><\/strong> &#8211; <strong><em>47<\/em><\/strong> sat\u0131r aral\u0131\u011f\u0131ndakiler &#8216;k\u00fc\u00e7\u00fckt\u00fcr&#8217;, <strong><em>49<\/em><\/strong> &#8211; <strong><em>55<\/em><\/strong> &#8216;k\u00fc\u00e7\u00fck e\u015fittir&#8217;, <strong><em>57<\/em><\/strong> &#8211; <strong><em>63<\/em><\/strong> &#8216;e\u015fittir&#8217; \u015fartlar\u0131n\u0131 uygulamaktad\u0131rlar.<\/p>\n<p><strong><em>65<\/em><\/strong> &#8211; <strong><em>71<\/em><\/strong>, <strong><em>73<\/em><\/strong> &#8211; <strong><em>79<\/em><\/strong> ve <strong><em>81<\/em><\/strong> &#8211; <strong><em>87.<\/em><\/strong> sat\u0131r aral\u0131\u011f\u0131ndaki metotlar s\u0131ras\u0131yla &#8216;%..%&#8217;, &#8216;..%&#8217; ve &#8216;%..&#8217; mant\u0131\u011f\u0131ndaki LIKE \u015fartlar\u0131n\u0131 uygulamaktad\u0131rlar.<\/p>\n<p><strong><em>18<\/em><\/strong> ile <strong><em>23.<\/em><\/strong> sat\u0131r aral\u0131\u011f\u0131ndaki &#8216;DebugField&#8217; isimli generic metot ise t\u00fcm &#8216;Func&lt;T&gt;&#8217; parametreli \u015fart metotlar\u0131nda lambda ile se\u00e7ilen property&#8217;inin kolon ad\u0131 olarak kullan\u0131labilmesi i\u00e7in string olarak ay\u0131rt edilebilmesi i\u015flevini ger\u00e7ekle\u015ftirmektedir.<\/p>\n<p>Ve son olarak <strong><em>89<\/em><\/strong> &#8211; <strong><em>90<\/em><\/strong> sat\u0131r aral\u0131\u011f\u0131nda bulunan &#8216;GenerateSql&#8217; metodu ise ilgili kriterin sorguya eklenebilmesi i\u00e7in uygun formatta olu\u015fturulmas\u0131ndan sorumludur.<\/p>\n<p>Tabi bu kod blo\u011funda kullan\u0131lan &#8216;QueryLogicalOperator&#8217; enum&#8217;\u0131 da a\u015fa\u011f\u0131daki gibi bir i\u00e7eri\u011fe sahiptir.<\/p>\n<div style=\"font-size:12px;\">\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public enum QueryLogicalOperator\r\n    {\r\n        And, Or, None\r\n    }\r\n<\/pre>\n<\/div>\n<\/li>\n<li><strong><em>Ad\u0131m 2<\/em><\/strong><br \/>\nS\u0131rada, art\u0131k olu\u015fturulan kriterlerin kullan\u0131laca\u011f\u0131 esas sorguyu temsil edecek olan &#8216;Query&#8217; s\u0131n\u0131f\u0131n\u0131n olu\u015fturulmas\u0131 vard\u0131r.<\/p>\n<div style=\"font-size:12px;\">\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public class Query&lt;T&gt;\r\n    {\r\n        string baseQuery = &quot;SELECT {0} FROM {1}&quot;;\r\n\r\n        List&lt;Criteria&lt;T&gt;&gt; criterias;\r\n        public Query(string tableNames) : this(&quot;*&quot;, tableNames)\r\n        { }\r\n\r\n        public Query(List&lt;Criteria&lt;T&gt;&gt; criterias, string tableNames) : this(&quot;*&quot;, tableNames)\r\n            =&gt; this.criterias = criterias;\r\n\r\n        public Query(string columnNames, string tableNames)\r\n        {\r\n            this.criterias = new();\r\n            baseQuery = String.Format(baseQuery, columnNames, tableNames);\r\n        }\r\n\r\n        public Query(Expression&lt;Func&lt;T, object&gt;&gt; method, string tableNames)\r\n        {\r\n            this.criterias = new();\r\n            NewExpression expression = method.Body as NewExpression;\r\n            List&lt;Expression&gt; arguments = expression.Arguments.ToList();\r\n\r\n            StringBuilder columns = new();\r\n            for (int i = 0; i &lt; arguments.Count; i++)\r\n            {\r\n                Expression argument = arguments&#x5B;i];\r\n                columns.Append(argument.ToString().Remove(0, argument.ToString().IndexOf(&quot;.&quot;) + 1));\r\n                if (i != arguments.Count - 1)\r\n                    columns.Append(&quot;, &quot;);\r\n            }\r\n            baseQuery = String.Format(baseQuery, columns, tableNames);\r\n        }\r\n\r\n        public void Add(Criteria&lt;T&gt; criteria)\r\n            =&gt; this.criterias.Add(criteria);\r\n\r\n        public string GenerateWhereClause()\r\n        {\r\n            StringBuilder whereClause = new();\r\n            whereClause.Append(&quot;Where &quot;);\r\n            for (int i = 0; i &lt; criterias.Count; i++)\r\n            {\r\n                Criteria&lt;T&gt; criteria = criterias&#x5B;i];\r\n                whereClause.Append(criteria.GenerateSql());\r\n                if (i != criterias.Count - 1)\r\n                    whereClause.Append(criteria.QueryOperator switch { QueryLogicalOperator.Or =&gt; &quot; OR &quot;, QueryLogicalOperator.And =&gt; &quot; AND &quot; });\r\n            }\r\n            return $&quot;{baseQuery} {whereClause.ToString()}&quot;;\r\n        }\r\n    }\r\n<\/pre>\n<\/div>\n<p>Bu s\u0131n\u0131f\u0131 da incelersek e\u011fer; <strong><em>3.<\/em><\/strong> sat\u0131rda olu\u015fturulacak base query format\u0131n\u0131 g\u00f6rmekteyiz. Bu query s\u00fcre\u00e7te gelecek olan kolon ve tablo bilgisine g\u00f6re \u015fekilleniyor olacakt\u0131r.<\/p>\n<p><strong><em>5.<\/em><\/strong> sat\u0131rda, olu\u015fturulacak query&#8217;de kullan\u0131lacak olan kriterlerin tutulaca\u011f\u0131 koleksiyon referans\u0131 mevcuttur.<\/p>\n<p><strong><em>6<\/em><\/strong> ile <strong><em>33.<\/em><\/strong> sat\u0131r aral\u0131\u011f\u0131na bakarsan\u0131z e\u011fer constructor metotlar\u0131n overload&#8217;lar\u0131 mevcuttur. Bu overload&#8217;lar\u0131 incelersek sorgulama s\u00fcrecinde kullan\u0131lacak kolon ve tablo isimlerini t\u00fcrl\u00fc \u015fekilde almakta ve &#8216;baseQuery&#8217;e basmaktad\u0131rlar. Bunlar\u0131n aras\u0131ndan tek dikkat edilmesi gereken <strong><em>18<\/em><\/strong> ile <strong><em>33.<\/em><\/strong> sat\u0131r aral\u0131\u011f\u0131nda constructor overload&#8217;\u0131d\u0131r. Bu overload sorguda kullan\u0131lacak olan kolonlar\u0131 &#8216;Func&lt;T&gt;&#8217; parametresi ile lambda e\u015fli\u011finde belirleyebilmemizi sa\u011flamaktad\u0131r. Yap\u0131sal olarak lambda ile anonymous bir nesne olarak bildirilen property&#8217;ler ilgili overload i\u00e7erisinde kolon ad\u0131 olarak alg\u0131lanarak ay\u0131klanmakta ve virg\u00fclle yanyana birle\u015ftirilip &#8216;baseQuery&#8217;de ilgili alana yaz\u0131lmaktad\u0131rlar.<\/p>\n<p><strong><em>35.<\/em><\/strong> sat\u0131rda ise generate edilecek sorguya ihtiya\u00e7 do\u011frultusunda kriterlerin eklenmesini sa\u011flayan &#8216;Add&#8217; fonksiyonu mevcuttur.<\/p>\n<p>Ve <strong><em>38<\/em><\/strong> ile <strong><em>50.<\/em><\/strong> sat\u0131r aral\u0131\u011f\u0131nda ise olu\u015fturulan &#8216;baseQuery&#8217; e\u015fli\u011finde kriterlerin harmanland\u0131\u011f\u0131 sorguyu olu\u015fturacak olan &#8216;GenerateWhereClause&#8217; metodu mevcuttur. Bu metot, kriterlerin &#8216;GenerateSql&#8217; metodunu tetikleyerek sorguya eklenebilir halde olu\u015fturulmalar\u0131n\u0131 ve &#8216;baseQuery&#8217; \u00fczerinde &#8216;Where&#8217; \u015fart\u0131 olarak eklenmelerini sa\u011flamakta ve nihai olarak sorguyu bizlere return etmektedir.\n<\/li>\n<li><strong><em>Ad\u0131m 3<\/em><\/strong><br \/>\nSon olarak query&#8217;i olu\u015fturma s\u00fcrecinde &#8216;Criteria&#8217; ve &#8216;Query&#8217; s\u0131n\u0131flar\u0131nda &#8216;Func&lt;T&gt;&#8217; parametreli fonksiyonlar\u0131 kullanabilmek i\u00e7in bir t\u00fcre ihtiyac\u0131m\u0131z olacakt\u0131r. Bu t\u00fcr veritaban\u0131ndaki tabloya kar\u015f\u0131l\u0131k gelecek olan entity modelidir. \u00c7\u00fcnk\u00fc ancak bir entity \u00fczerinden g\u00f6n\u00fcl rahatl\u0131\u011f\u0131yla tip g\u00fcvenli sorgulama, kolon yahut \u015fart belirleme i\u015flemlerini tutarl\u0131 bir \u015fekilde ger\u00e7ekle\u015ftirebiliriz. Dolay\u0131s\u0131yla a\u015fa\u011f\u0131daki gibi &#8216;Products&#8217; tablosunu modelleyen &#8216;Product&#8217; s\u0131n\u0131f\u0131n\u0131 in\u015fa edelim.<\/p>\n<div style=\"font-size:12px;\">\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public class Product\r\n    {\r\n        public int Id { get; set; }\r\n        public string Name { get; set; }\r\n        public int Stock { get; set; }\r\n        public float Price { get; set; }\r\n    }\r\n<\/pre>\n<\/div>\n<\/li>\n<li><strong><em>Ad\u0131m 4<\/em><\/strong><br \/>\nArt\u0131k sorgular\u0131m\u0131z\u0131 olu\u015fturabilir ve kriterlerimizi belirleyebiliriz.<\/p>\n<p>Misal, manuel parametreli fonksiyonlar\u0131 kullanarak &#8216;Name&#8217; i\u00e7erisinde &#8216;i&#8217; harfi ge\u00e7en ve &#8216;Stock&#8217; bilgisi 100&#8217;den b\u00fcy\u00fck olan \u00fcr\u00fcnleri getirecek olan sorguyu olu\u015ftural\u0131m.<\/p>\n<div style=\"font-size:12px;\">\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nQuery&lt;Product&gt; query = new(&quot;Products&quot;);\r\nquery.Add(Criteria&lt;Product&gt;.Contains(&quot;Name&quot;, &quot;i&quot;, QueryLogicalOperator.And));\r\nquery.Add(Criteria&lt;Product&gt;.GreaterThan(&quot;Stock&quot;, 100));\r\nstring _query = query.GenerateWhereClause();\r\n\r\nConsole.WriteLine(_query);\r\n<\/pre>\n<\/div>\n<p>Bu \u00e7al\u0131\u015fma neticesinde a\u015fa\u011f\u0131daki sorgu \u00fcretilecektir.<br \/>\n<code style=\"font-size:15px;color:red;\"><strong>SELECT * FROM Products Where Name Like '%i%' AND Stock > 100<\/strong><\/code><\/p>\n<p>Ya da &#8216;Price&#8217;\u0131 10&#8217;dan b\u00fcy\u00fck e\u015fit olan veya &#8216;Name&#8217; de\u011feri &#8216;\u00c7anta&#8217; olan \u00fcr\u00fcnlerin sadece &#8216;Id&#8217; ve &#8216;Name&#8217; bilgilerini getirecek sorguyu &#8216;Func&lt;T&gt;&#8217; e\u015fli\u011finde olu\u015ftural\u0131m.<\/p>\n<div style=\"font-size:12px;\">\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nQuery&lt;Product&gt; query = new(p =&gt; new\r\n{\r\n    p.Id,\r\n    p.Name\r\n}, &quot;Products&quot;);\r\nquery.Add(Criteria&lt;Product&gt;.GreaterThanOrEqual(p =&gt; p.Price, 10, QueryLogicalOperator.Or));\r\nquery.Add(Criteria&lt;Product&gt;.Equal(p =&gt; p.Name, &quot;\u00c7anta&quot;, QueryLogicalOperator.None));\r\nstring _query = query.GenerateWhereClause();\r\n<\/pre>\n<\/div>\n<p>Bu \u00e7al\u0131\u015fman\u0131n da \u00e7\u0131kt\u0131s\u0131 a\u015fa\u011f\u0131daki gibi olacakt\u0131r.<br \/>\n<code style=\"font-size:15px;color:red;\"><strong>SELECT Id, Name FROM Products Where Price >= 10 OR Name = '\u00c7anta'<\/strong><\/code>\n<\/li>\n<\/ul>\n<p>\u0130\u015fte, g\u00f6r\u00fcld\u00fc\u011f\u00fc \u00fczere Query Object pattern her bir veritaban\u0131 sorgusunu, temsil eden bir generic nesne olarak tasarlamam\u0131z\u0131 ve ihtiyaca d\u00f6n\u00fck sorgular\u0131 tip g\u00fcvenli bir \u015fekilde fonksiyonaliteler e\u015fli\u011finde olu\u015fturmam\u0131z\u0131 sa\u011flamakta ve b\u00f6ylece geli\u015ftiricinin sorgu s\u00fcre\u00e7lerinde y\u00fck\u00fcn\u00fc minimuma \u00e7ekip olas\u0131 maliyetlerden geli\u015ftirme s\u00fcrecini ar\u0131nd\u0131rmaktad\u0131r.<\/p>\n<p>Tabi ki de bu pattern&#8217;\u0131 in\u015fa ederken genel stratejisinin haricinde geri kalan \u00f6zellik ve fonksiyonlar\u0131 kendi ihtiya\u00e7 ve d\u00fc\u015f\u00fcncenize g\u00f6re tasarlayabilir ve \u00e7ok farkl\u0131 niteliklerde i\u015flevsellikler ekleyerek generate edilecek sorgu \u00e7e\u015fitlili\u011fini azami miktarda detayland\u0131rabilir ve artt\u0131rabilirsiniz.<\/p>\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<p>Not : \u00d6rnek projeyi a\u015fa\u011f\u0131daki github adresinden edinebilirsiniz.<br \/>\n<a href=\"https:\/\/github.com\/gncyyldz\/QueryObjectDesignPatternExample\" rel=\"noopener\" target=\"_blank\">https:\/\/github.com\/gncyyldz\/QueryObjectDesignPatternExample<\/a><\/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, G\u00fcn\u00fcm\u00fczde bir\u00e7ok uygulamada veritaban\u0131 i\u015flemleri i\u00e7in yayg\u0131n olarak ORM(Object Relational Mapping) yakla\u015f\u0131m\u0131 tercih ediliyor olsa da bir\u00e7ok k\u00fc\u00e7\u00fck ve orta \u00f6l\u00e7ekli \u015firket taraf\u0131ndan ve hatta geleneksel olarak radikal de\u011fi\u015fiklikleri kald\u0131ramayacak kadar k\u00f6kl\u00fc framework&#8217;lere&#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":24883,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[153],"tags":[4568,4569,4567,4566,4571,4570],"class_list":["post-24873","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-design-pattern","tag-query-object","tag-query-object-d-p","tag-query-object-design-pattern","tag-query-object-tasarim-deseni","tag-sorgu-nesnesi","tag-sorgu-nesnesi-tasarim-deseni"],"amp_enabled":true,"_links":{"self":[{"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/posts\/24873","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=24873"}],"version-history":[{"count":66,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/posts\/24873\/revisions"}],"predecessor-version":[{"id":24943,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/posts\/24873\/revisions\/24943"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/media\/24883"}],"wp:attachment":[{"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/media?parent=24873"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/categories?post=24873"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/tags?post=24873"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}