{"id":1300,"date":"2012-07-23T13:47:24","date_gmt":"2012-07-23T12:47:24","guid":{"rendered":"http:\/\/soci.hu\/blog\/?p=1300"},"modified":"2012-07-23T18:45:27","modified_gmt":"2012-07-23T17:45:27","slug":"sp-vs-or-mapper","status":"publish","type":"post","link":"https:\/\/soci.hu\/blog\/index.php\/2012\/07\/23\/sp-vs-or-mapper\/","title":{"rendered":"SP vs. OR mapper"},"content":{"rendered":"<p>Az el\u0151z\u0151 bejegyz\u00e9sb\u0151l a kommentek alapj\u00e1n lehet az j\u00f6tt le, hogy \u00e9n minden dolgot OR mapperrel val\u00f3s\u00edtan\u00e9k meg. Csud\u00e1kat, sz\u00f3 sincs err\u0151l.<\/p>\n<p>N\u00e9zz\u00fcnk egy p\u00e9ld\u00e1t. Az el\u0151z\u0151 architekt\u00fara tervemben (ami protot\u00edpus majd framework is lett, nem csak terv) NHibernate \u00e9s Oracle alapon k\u00e9sz\u00fclt az app. Sok m\u00e1s mellett tetsz\u0151leges orsz\u00e1gban haszn\u00e1lhat\u00f3 emberneveket kellett tudni t\u00e1rolni, ez\u00e9rt a db terv el\u00e9g \u00e1ltal\u00e1nos lett. Person-PersonName-PersonNamePart, ez a 3 t\u00e1bla volt a f\u0151 v\u00e1z. PersonNameType, PersonNamePartType, ezek enum jelleg\u0171 lookup t\u00e1bl\u00e1k.<br \/>\nEgy lek\u00e9rdez\u00e9s c\u00e9lja visszaadni tetsz\u0151leges n\u00e9v komponens alapj\u00e1n a beteg nev\u00e9t. Azaz a PersonNamePart t\u00e1bla egy oszlop\u00e1ban kellett keresni, ez j\u00f3l indexelhet\u0151, hat\u00e9kony lek\u00e9rdez\u00e9s. Ut\u00e1na j\u00f6tt a m\u00f3k\u00e1sabb r\u00e9sz. A PersonNamePartb\u00f3l vissza kellett navig\u00e1lni a PersonName-re, onnan a Personre, majd a megjelen\u00edt\u00e9s miatt vissza le az \u00f6sszes PersonName-re \u00e9s onnan tov\u00e1bb a PersonNamePartra.<br \/>\nEzt a lek\u00e9rdez\u00e9st el\u0151sz\u00f6r meg\u00edrtam P\/L SQL-ben, hogy l\u00e1ssam, kb. mit akarok csin\u00e1lni, ez mennyire hat\u00e9kony, kell-e hozz\u00e1 Cluster (nem clustered, ez oracle, ez teljesen m\u00e1s) index az IO cs\u00f6kkent\u00e9s\u00e9re, stb.<br \/>\nAmikor a lek\u00e9rdez\u00e9ssel el\u00e9gedett voltam, elkezdtem \u00e1t\u00edrni az NHibernate LINQ provider\u00e9re. A c\u00e9lom az volt, hogy a query gondolkod\u00e1sm\u00f3dj\u00e1t pontosan visszat\u00fckr\u00f6zze a LINQ query, \u00edgy rem\u00e9lhet\u0151leg a gener\u00e1lt sql is hasonl\u00f3an hat\u00e9kony lesz. Sajnos azonban a k\u00eds\u00e9rlet kudarc volt. Az NHibernate LINQ providere egyszer\u0171en nem implement\u00e1lta amit \u00e9n akartam (ha j\u00f3l eml\u00e9kszem Take(n) ut\u00e1n Select). Megn\u00e9ztem a forr\u00e1s\u00e1t, ott volt egy nagy b\u00fcd\u00f6s throw new NotImplementedException().<br \/>\nMi maradt? Sp, aminek a kimeneti joinolt sorait az NHibernate alak\u00edtotta vissza entit\u00e1sokk\u00e1 (ez viszont nagyon \u00fcgyes r\u00e9sze az NHibnek.)<br \/>\nAzaz a lek\u00e9rdez\u00e9s a lehet\u0151 leghat\u00e9konyabb volt, de a v\u00e9g\u00e9n m\u00e9gis a domain modellel dolgoztam, ami v\u00e9g\u00fcl szimpatikus hibrid lett, b\u00e1r jobb lett volna tiszt\u00e1n LINQ-ban meg\u00edrni.<br \/>\nMi lett volna, hogy rendesen meg\u00edrt\u00e1k volna a LINQ providert? Megn\u00e9ztem volna a gener\u00e1lt SQL-t, \u00e9s ha az megfelel\u0151en hat\u00e9kony lett volna, akkor maradt volna az.<br \/>\nHa nincs r\u00e1 k\u00fcl\u00f6n\u00f6sebb okom, \u00e9n szeretem a logik\u00e1kat C#-ban \u00edrni. Az objektumorient\u00e1lts\u00e1g miatt j\u00f3l lehet szervezni az \u00f6sszetettebb k\u00f3dokat, sokkal jobban, mint a procedur\u00e1lis TSQL-ben.<br \/>\nLehet mem\u00f3ri\u00e1ban cache-lni dolgokat, SQL Serveren bel\u00fcl nem nagyon. Az appszervereket sokkal k\u00f6nnyebb horizont\u00e1lisan sk\u00e1l\u00e1zni mint a DB-t. Magyarul egym\u00e1s mell\u00e9 berakni sok azonos szervert, m\u00e9g ha ez marh\u00e1ra nem is trivi\u00e1lis, de legal\u00e1bb lehets\u00e9ges. Emiatt a DB-r\u0151l terhel\u00e9st levenni nem kell f\u00e9lnetek, mindenk\u00e9ppen \u00fcdv\u00f6s tev\u00e9kenys\u00e9g.<br \/>\nViszont, ha az adatokhoz k\u00f6zel kell m\u0171veleteket v\u00e9gezni, akkor nem fogok feleslegesen \u00e1tvinni nagysz\u00e1m\u00fa sort az appszerverre. Ha egy gyakran fut\u00f3 kritikus tranzakci\u00f3 hossza fontos, akkor lehet spbe rakom. Ha sok sort \u00e9rint a m\u0171velet nem hozom ki \u0151ket a dbb\u0151l.<\/p>\n<p>Pr\u00f3b\u00e1lok p\u00e1r p\u00e9ld\u00e1t konstru\u00e1lni, illusztr\u00e1land\u00f3 az el\u0151bbieket.<\/p>\n<p>1. Be kell olvasni 100 sort egy t\u00e1bl\u00e1b\u00f3l, lefuttatni valami \u00f6sszetett m\u0171veletet rajta, amely kb. 1000 sornyi programk\u00f3dnak felel meg, majd az eredm\u00e9nyt vissza\u00edrni egy m\u00e1sik t\u00e1bl\u00e1ba, amely kb. 20 sornyi insertet jelent. OR mapper. A bonyolult logika val\u00f3sz\u00edn\u0171leg er\u0151sebb \u00e9rv lesz, mint az, hogy 100 sort \u00e1t kell vinni a dr\u00f3ton, illetve, hogy 2 roundtrippel j\u00e1r a m\u0171velet. Mivel a logika C#-ban lesz, k\u00f6nny\u0171 lesz teszteket \u00edrni r\u00e1 (a db k\u00f6nnyen kifake-elhet\u0151), k\u00f6nnyebb lesz karbantartani, ha m\u00f3dos\u00edtani kell.<br \/>\nHa esetleg az eg\u00e9sznek egy tranzakci\u00f3ban kell lenni, \u00e9s a round tripek ideje jelent\u0151sen ny\u00fajtja a tranzakci\u00f3k fut\u00e1si idej\u00e9t, ami miatt az esetleg szigor\u00fabb izol\u00e1ci\u00f3s szinten fut\u00f3 tranzakci\u00f3k elkezdenek torl\u00f3dni akkor, \u00e9s csakis akkor kezden\u00e9k el fil\u00f3zni az spn. De ezt csak m\u00e9r\u00e9ssel lehet eld\u00f6nteni, mert az sp eset\u00e9n meg val\u00f3sz\u00edn\u0171leg a logika lesz lassabb, \u00edgy lehet t\u00f6bbet veszt\u00fcnk, mint nyer\u00fcnk.<\/p>\n<p>2. Be kell olvasni 5 t\u00e1bl\u00e1b\u00f3l 1 sort, ezek alapj\u00e1n d\u00f6nteni, majd vissza\u00edrni 2 t\u00e1bl\u00e1ba 1-1 sort. Az alapeset ugye az, hogy megpr\u00f3b\u00e1ljuk OR mapperen kereszt\u00fcl megoldani a dolgot, majd bel\u00e1tni, hogy az el\u00e9g hat\u00e9kony-e, ha nem akkor \u00e1tt\u00e9r\u00fcnk sp-re. NHibernate vagy EF Extension Pack Future-\u00f6kkel az 5 select val\u00f3sz\u00edn\u0171leg kiadhat\u00f3 1 roundtrip alatt, ha nincs k\u00f6z\u00f6tt\u00fck f\u00fcgg\u0151s\u00e9g. Ha van, akkor lehet, hogy join-nal vagy navig\u00e1c\u00f3s rel\u00e1ci\u00f3kon haladva m\u00e9g mindig megoldhat\u00f3 1 roundtrip alatt. Ha nem, akkor nem. A vissza\u00edr\u00e1sok norm\u00e1lis OR mapper eset\u00e9n 1 roundtrip alatt v\u00e9grehajthat\u00f3k (batching), \u00edgy 2 roundtrip alatt megvan a feladat. Val\u00f3sz\u00edn\u0171leg b\u0151ven belef\u00e9r, marad az OR mapper.<\/p>\n<p>3. Le kell t\u00f6r\u00f6lni sok sort, ahol a DueDate nem mai d\u00e1tum. Egy\u00e9rtelm\u0171en sp, semmi \u00e9rtelme OR mapperbe beh\u00fazni a t\u00f6rlend\u0151 sorokat, k\u00f6nnyed\u00e9n megfogalmazhat\u00f3 a felt\u00e9tel egy sima SQL where-ben. Hozz\u00e1teszem, NHibbel lehet delete \u00e9s update m\u0171veleteket is kiadni entit\u00e1s fogalmak haszn\u00e1lat\u00e1val, \u00edgy ann\u00e1l ezt se spzn\u00e9m, a gener\u00e1lt sql az lenne, ami k\u00e9zzel be\u00edrn\u00e9k az spbe, csak direkt sqlk\u00e9nt. Akkor meg minek sp-zzek?<\/p>\n<p>4. Be kell sz\u00farni 500 sort, nagyon gyorsan, naponta sokszor. pl. laborg\u00e9pek ok\u00e1dj\u00e1k magukb\u00f3l az eredm\u00e9nyeket, ezeket kell elt\u00e1rolni. Ez m\u00e1r \u00e9rdekesebb k\u00e9rd\u00e9s. Els\u0151 k\u00f6rben azt mondan\u00e1nk, OR mapper erre nem val\u00f3. Az els\u0151 gondolatom az ilyenre valamilyen bulk copy megold\u00e1s lenne, pl. SQL Server eset\u00e9n SqlBulkCopy oszt\u00e1llyal. De pl. Oracle eset\u00e9n van un. Array Binding, amivel a bulk m\u0171veletekkel k\u00f6zel azonos teljes\u00edtm\u00e9nyt lehet el\u00e9rni, a bulk m\u0171veletek limit\u00e1ci\u00f3i (nem lehet trigger a t\u00e1bl\u00e1n, stb.) n\u00e9lk\u00fcl. Ami meglep\u0151, hogy a NHibernate oracle eset\u00e9n kihaszn\u00e1lja az array bindingot, \u00e9s nem csak egyszer\u0171en batcheli a m\u0171veleteket, de array bindinggel k\u00fcldi be. Emiatt veszett gyorsan tud besz\u00farni, \u00edgy NHib eset\u00e9n sim\u00e1n OR mappert haszn\u00e1ln\u00e9k erre is. Egy konkr\u00e9t m\u00e9r\u00e9semben 10000 sor besz\u00far\u00e1sa \u00edgy n\u00e9zett ki  Oracle-be (fejb\u0151l mondom, de a nagys\u00e1grendek j\u00f3l lesznek):<br \/>\n1. NHibernate identity id generator (othodox SQL Serveres gondolkod\u00e1sm\u00f3d): 52 sec<br \/>\n2. ADO.NET soronk\u00e9nti insert: 12 sec<br \/>\n3. NHibernate hilo id gener\u00e1torral: 2.7 sec<br \/>\n4. ADO.NET Array Bindinggal: 2.2 sec<br \/>\n5. Direct Path Loading: 2.1 sec<\/p>\n<p>Mik a tanuls\u00e1gok ebb\u0151l a m\u00e9r\u00e9sb\u0151l?<br \/>\nA. Az identity alap\u00fa ID gener\u00e1l\u00e1s meg\u00f6li az insertek teljes\u00edtm\u00e9ny\u00e9t (1. \u00e9s 2. p\u00e9lda alapj\u00e1n)<br \/>\nB. A sok roundtrip mindenk\u00e9ppen k\u00e1ros, emiatt lett lass\u00fa 2. is, mivel itt nem volt OR mapper overhead.<br \/>\nC. Az NHib elk\u00e9peszt\u0151en gyors volt (3. p\u00e9lda), csak 20%-kal lassabb volt, mint az Array Binding nyersen haszn\u00e1lva (2.2\/2.7).<br \/>\nD. Az Array Binding eszement gyors, SQL Serveren a t\u00e1bla t\u00edpus\u00fa param\u00e9terekkel lehet hasonl\u00f3t el\u00e9rni, de ehhez nem tudok OR mapper t\u00e1mogat\u00e1st (mivel ehhez explicit kell fogad\u00f3 k\u00f3dot \u00edrni, az or\u00e1hoz NEM).<br \/>\nE. A bulk copy mindenhol a leggyorsabb, de az or\u00e1n\u00e1l ez nagyon limit\u00e1lt, le is van \u00edrva, hogy arra gy\u00farnak, hogy az array binding legyen ugyanolyan gyors, \u00edgy kiv\u00e1lthatja azt.<\/p>\n<p>Azaz, ha megfelel\u0151en optimaliz\u00e1lt az OR mapper adatel\u00e9r\u00e9se, akkor m\u00e9g olyan esetekben is haszn\u00e1lhat\u00f3, ahol els\u0151 k\u00f6rben nem jutna az esz\u00fcnkbe.<\/p>\n<p>5. K\u00e9t t\u00e1bla k\u00f6z\u00f6tt kell \u00e1tmozgatni sorokat, egyszer\u0171 lek\u00e9pez\u00e9sek ment\u00e9n. Sp, insert-select \u00e9s delete, tranzakci\u00f3ban.<\/p>\n<p>6. <a href=\"http:\/\/martinfowler.com\/eaaCatalog\/pessimisticOfflineLock.html\">Pessimistic Offline Lock<\/a> pattern implement\u00e1ci\u00f3ban volt a k\u00f6vetkez\u0151. Meg kell n\u00e9zni, l\u00e9tezik-e lock egy er\u0151forr\u00e1sra, ez egy egy sz\u0171rt select. Ha nem, akkor besz\u00farni egyet, ha igen, besz\u00farni egy v\u00e1rakoz\u00f3 sort. Mindezt serializable izol\u00e1ci\u00f3s szinten, mivel meg kell akad\u00e1lyozni fantom sorok besz\u00far\u00e1st a select \u00e9s az insert k\u00f6z\u00f6tt (or\u00e1nak is van ilyenje, b\u00e1r nem lockol mint az Sql server alapban, hanem \u00fagy m\u0171k\u00f6dik, mint az <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms189050%28v=sql.105%29.aspx\">RCSI<\/a> az SQL servern\u00e9l).<br \/>\n\u00c9rezhet\u0151en itt \u00e9szn\u00e9l kell lenni, mivel ha sokszor fut le a folyamat, akkor a serializable miatt lass\u00fa lehet a dolog. Design szempontb\u00f3l \u00e9rtelemszer\u0171en az offline lockkal v\u00e9deni k\u00edv\u00e1nt dolgok lek\u00e9rdez\u00e9se NEM a serializable tranzakci\u00f3ban volt. A v\u00e9dend\u0151 lek\u00e9rdez\u00e9s el\u0151bb lefut, majd ut\u00e1na j\u00f6n a lock fog\u00e1sa, \u00e9s ha siker\u00fcl, megkapja a kliens az eredm\u00e9nyt, ha nem, akkor eldobjuk a lek\u00e9rdez\u00e9se eredm\u00e9ny\u00e9t. Ez pazarl\u00e1s, ha \u00fctk\u00f6z\u00e9s van, de nem sz\u00e1m\u00edtunk sok \u00fctk\u00f6z\u00e9sre. Ha egy tranzakci\u00f3ban lenne a k\u00e9t feladat torl\u00f3d\u00e1s lenne, ha el\u0151bb a lock, azt\u00e1n a m\u0171velet, akkor meg sikertelen m\u0171velet eset\u00e9n (pl. secu beint) t\u00f6r\u00f6lni kellene a lockot, de k\u00f6zben m\u00e1r lehet m\u00e1s v\u00e1r r\u00e1&#8230;<br \/>\nEzt a feladatot OR mapperrel \u00edrtam meg. Nem tudok pontos v\u00e9grehajt\u00e1si id\u0151t mondani, de ha j\u00f3l eml\u00e9kszem kb. 20 ms volt a teljes lock vizsg\u00e1lat ideje. Ha serializable szinten egy er\u0151forr\u00e1son versengen\u00e9nek a folyamatok, akkor m\u00e1sodpercenk\u00e9nt 50-n\u00e9l t\u00f6bbet nem tudna a szerver v\u00e9grehajtani. Val\u00f3j\u00e1ban azonban sz\u00f3rnak a lockoland\u00f3 er\u0151forr\u00e1sok, \u00edgy a serializable nem fog jelent\u0151s torl\u00f3d\u00e1st okozni (megfelel\u0151 csak indexekkel persze).<br \/>\nSokan szerintem ezt kap\u00e1sb\u00f3l SP-ben \u00edrn\u00e1k meg. Mit nyern\u00e9nk vele? Mit akarunk minimaliz\u00e1lni? Az SQL szint\u0171 tranzakci\u00f3 idej\u00e9t. A tranzakci\u00f3 kb. \u00edgy n\u00e9zne ki:<br \/>\nbegin tran<br \/>\nselect &#8230;<br \/>\nif () insert&#8230;<br \/>\nelse m\u00e1sik insert&#8230;<br \/>\ncommit<\/p>\n<p>A k\u00e9rd\u00e9s, ezek ideje hogy ar\u00e1nylik a roundtripek \u00e1ltal megn\u00f6velt id\u0151h\u00f6z? 3 roundtrip van, 1 select, 1 valamilyen insert \u00e9s egy commit. Ha a roundtrip ideje mondjuk 3ms, akkor 9 ms a roundtrip overheadje. Ha az SQL m\u0171veletek kb. 10ms-ig tartottak, akkor k\u00e9tszer olyan gyors lehet az sp-s megold\u00e1s. Azaz itt elgondolkodtat\u00f3 a dolog, de megint, \u00e9n csak konkr\u00e9t m\u00e9r\u00e9sek alapj\u00e1n \u00e1lln\u00e9k neki \u00e1trefactorolni a megold\u00e1st spre, ilyen spekulat\u00edv \u00faton nem. Hisz ha a roundtrip val\u00f3j\u00e1ban csak 500 usec, akkor m\u00e1ris 1 napig felesleges dologgal m\u00falattuk az id\u0151t.<\/p>\n<p>7. Sok id alapj\u00e1n kell behozni p\u00e1r sz\u00e1z sort. Lehets\u00e9ge megold\u00e1s OR-mapper future queryvel, egy batchben, de ennek h\u00e1tr\u00e1nya, hogy pl. SQL Servern\u00e9l nem lehet 1-2 ez\u00e9rn\u00e9l t\u00f6bb param\u00e9tert defini\u00e1lni, \u00edgy a gener\u00e1lt sql nem lesz v\u00e9grehajthat\u00f3. Itt spt \u00edrtunk, amely oracle collection param\u00e9terk\u00e9nt vette \u00e1t a kulcsok list\u00e1j\u00e1t, bel\u00fcl pedig joinoltunk az alapt\u00e1bl\u00e1hoz. SQL Servern\u00e9l ezt t\u00e1bla t\u00edpus\u00fa param\u00e9terrel csin\u00e1ltam volna meg. A bemenetet eleg\u00e1nsan \u00e1t lehetett adni, mivel az NHibben lehet saj\u00e1t t\u00edpust defini\u00e1lni, \u00edgy Guid t\u00f6mb t\u00edpus direkben \u00e1tpasszolhat\u00f3 volt az spbe.<\/p>\n<p>M\u00e1s. A m\u00e1r eml\u00edtett architekt\u00far\u00e1ban volt sok olyan cross-cutting concern, amit db szinten implement\u00e1lni v\u00e9res lett volna. P\u00e9ld\u00e1ul a WCF-b\u0151l kij\u00f6v\u0151 objektum gr\u00e1fot m\u00f3dos\u00edtani kellett, mivel sor (entit\u00e1s) is mez\u0151 (property) szint\u0171 ACL secu miatt meg kellett metszeni a kimenete f\u00e1t (gr\u00e1fot, mikor-mit), property-k \u00e9rt\u00e9k\u00e9t kimaszkolni, de k\u00f6zben feljegyezni a maszkoltakat, sz\u00f6veget nyelvi ford\u00edt\u00e1s\u00e1t beinjekt\u00e1lni a gr\u00e1f tetsz\u0151leges hely\u00e9re, tetsz\u0151leges entit\u00e1st kieg\u00e9sz\u00edt\u0151 adatokat belerakni a fa megfelel\u0151 r\u00e9sz\u00e9re, be kellett k\u00fcldeni minden tranzakci\u00f3 nyit\u00e1sa ut\u00e1n egy user \u00e9s tran azonos\u00edt\u00f3t, offline lock inform\u00e1ci\u00f3t, stb. Ezek nagyon komplex feladatok voltak, amelyeket r\u00e1ad\u00e1sul millisecundum nagys\u00e1grend\u0171 id\u0151 alatt kellett tudni megcsin\u00e1lni t\u00edzezer elem feletti gr\u00e1fokra is. Ezt \u00e9n dbben nem tudtam volna megcsin\u00e1lni, intenz\u00edv appszerver szint\u0171 cache-el\u00e9ssel, illetve kihaszn\u00e1lva a .NET adatstrukt\u00far\u00e1it sikerrel \u00e9s eleg\u00e1nsan (k\u00f6zpontilag implement\u00e1lva, mint az AOP-ban) megoldottuk.<br \/>\nHa viszont ilyen mindent kereszt\u00fclv\u00e1g\u00f3 k\u00f6vetelm\u00e9nyekt\u0151l hemzseg a feladat, akkor ez ember k\u00e9tszer is meggondolja, hogy kil\u00e9pjen az entit\u00e1sok, a logikai modell vil\u00e1g\u00e1b\u00f3l, \u00e9s elkezdjen spzni, mivel az spkre r\u00e1h\u00fazni ezeket a megold\u00e1sokat neh\u00e9zkes.<br \/>\nSz\u00f3val az OR mapper vs. sp k\u00e9rd\u00e9s igen komplex, nem lehet 2 perc alatt d\u00f6nteni r\u00f3la, \u00e9s mindkett\u0151nek megvan a helye, feladatonk\u00e9nt egyes\u00e9vel kell eld\u00f6nteni, melyiket haszn\u00e1ljuk.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Az el\u0151z\u0151 bejegyz\u00e9sb\u0151l a kommentek alapj\u00e1n lehet az j\u00f6tt le, hogy \u00e9n minden dolgot OR mapperrel val\u00f3s\u00edtan\u00e9k meg. Csud\u00e1kat, sz\u00f3 sincs err\u0151l&#8230;.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[8,75,25,49,10,11,13,74,53,4],"tags":[],"class_list":["post-1300","post","type-post","status-publish","format-standard","hentry","category-net","category-net-4","category-adonet","category-architektura","category-c","category-clr","category-design","category-entity-framework","category-linq","category-szakmai-elet"],"_links":{"self":[{"href":"https:\/\/soci.hu\/blog\/index.php\/wp-json\/wp\/v2\/posts\/1300","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/soci.hu\/blog\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/soci.hu\/blog\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/soci.hu\/blog\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/soci.hu\/blog\/index.php\/wp-json\/wp\/v2\/comments?post=1300"}],"version-history":[{"count":5,"href":"https:\/\/soci.hu\/blog\/index.php\/wp-json\/wp\/v2\/posts\/1300\/revisions"}],"predecessor-version":[{"id":1305,"href":"https:\/\/soci.hu\/blog\/index.php\/wp-json\/wp\/v2\/posts\/1300\/revisions\/1305"}],"wp:attachment":[{"href":"https:\/\/soci.hu\/blog\/index.php\/wp-json\/wp\/v2\/media?parent=1300"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/soci.hu\/blog\/index.php\/wp-json\/wp\/v2\/categories?post=1300"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/soci.hu\/blog\/index.php\/wp-json\/wp\/v2\/tags?post=1300"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}