Çözüldü Generic repository nedir?

Bu konu çözüldü olarak işaretlenmiştir. Çözülmediğini düşünüyorsanız konuyu rapor edebilirsiniz.
Çözüm
OOP kullanan sistemlerde elindeki data objesini repository'e kaydetme islemini abstract etmene yarar her ikisi de.

Generic ile generic olmayanin farki adi ustunde birinin generic olmasi.

Bir tane Generic Repository class'i tanimlarsin ( gerekirse abstract ) ve repo'ya kaydetmek istedigin objeyi buna verirsin. Repo her ne ise o da adaptif olarak kaydeder. Istersen Redis, istersen postgresql vs.

Repository Pattern ile, o objenin kendisinden sorumlu bir repository implementasyonu olur. Java tarafinda Spring bunu kendi interface'leri ile yapiyor. .NET icin de eminim cok benzeri vardir.


Bunun yapilmasindaki esas mantik su, repository islemlerini kodun geri kalanindan ayirmak istiyoruz. Al bunu kaydet, bana bunlari getir gibi islemleri DRY ve SOLID prensiplerine uygun sekilde yapmamiza olanak sagliyor.

Yine ornegi Java tarafindan vericem .NET API'sine hakim olmadigim icin:

Kod:
interface UserRepository extends CrudRepository<User, Long>


interface ProductRepository extends JpaRepository<Product, String>

Ustte hem "user" hem de "product" icin 2 tane Repository interface tanimi yaptim. Bunlar "Repository Pattern" e uygun.

Tanimlamadaki interface'lere dikkat edersen bir tanesi "CrudRepository" extend ediyor, diger "JpaRepository". Bunlar framework'un kendisinin yazdigi "Generic Repository" patternine uygun.

Boylece demis oluyorum ki bana bir UserRepository implemente et ve bununla sadece Crud operasyonlari yapacagim.

Digerinde de daha gelismis ozelliklere sahip JPA repository ozellikleri yapacagim.

JPA Repository si de polimorfik olarak zaten Crud repository'sinin super-seti.

Karisik gibi gelebilir ama aslinda tum bu islemler ustte yazdigim gibi neredeyse her ORM class'i icin ortak kullanilan save, update, delete, page, query vs operasyonlarina ayri ayri kod yazmamak ve projenin geri kalaninda decouple etmek icin yaptigimiz tanimlamalar.

ORM kullaniliyorsa kullanilmali, cunku daha standardize hale getiriyor kodu.
OOP kullanan sistemlerde elindeki data objesini repository'e kaydetme islemini abstract etmene yarar her ikisi de.

Generic ile generic olmayanin farki adi ustunde birinin generic olmasi.

Bir tane Generic Repository class'i tanimlarsin ( gerekirse abstract ) ve repo'ya kaydetmek istedigin objeyi buna verirsin. Repo her ne ise o da adaptif olarak kaydeder. Istersen Redis, istersen postgresql vs.

Repository Pattern ile, o objenin kendisinden sorumlu bir repository implementasyonu olur. Java tarafinda Spring bunu kendi interface'leri ile yapiyor. .NET icin de eminim cok benzeri vardir.


Bunun yapilmasindaki esas mantik su, repository islemlerini kodun geri kalanindan ayirmak istiyoruz. Al bunu kaydet, bana bunlari getir gibi islemleri DRY ve SOLID prensiplerine uygun sekilde yapmamiza olanak sagliyor.

Yine ornegi Java tarafindan vericem .NET API'sine hakim olmadigim icin:

Kod:
interface UserRepository extends CrudRepository<User, Long>


interface ProductRepository extends JpaRepository<Product, String>

Ustte hem "user" hem de "product" icin 2 tane Repository interface tanimi yaptim. Bunlar "Repository Pattern" e uygun.

Tanimlamadaki interface'lere dikkat edersen bir tanesi "CrudRepository" extend ediyor, diger "JpaRepository". Bunlar framework'un kendisinin yazdigi "Generic Repository" patternine uygun.

Boylece demis oluyorum ki bana bir UserRepository implemente et ve bununla sadece Crud operasyonlari yapacagim.

Digerinde de daha gelismis ozelliklere sahip JPA repository ozellikleri yapacagim.

JPA Repository si de polimorfik olarak zaten Crud repository'sinin super-seti.

Karisik gibi gelebilir ama aslinda tum bu islemler ustte yazdigim gibi neredeyse her ORM class'i icin ortak kullanilan save, update, delete, page, query vs operasyonlarina ayri ayri kod yazmamak ve projenin geri kalaninda decouple etmek icin yaptigimiz tanimlamalar.

ORM kullaniliyorsa kullanilmali, cunku daha standardize hale getiriyor kodu.
 
Çözüm
OOP kullanan sistemlerde elindeki data objesini Repository'e kaydetme islemini abstract etmene yarar her ikisi de.

Generic ile generic olmayanin farki adi ustunde birinin generic olmasi.

Bir tane Generic Repository Class'i tanimlarsin ( gerekirse abstract ) ve Repo'ya kaydetmek istedigin objeyi buna verirsin. Repo her ne ise o da adaptif olarak kaydeder. Istersen Redis, istersen PostgreSQL vs.

Repository Pattern ile, o objenin kendisinden sorumlu bir repository implementasyonu olur. Java tarafinda Spring bunu kendi Interface'leri ile yapiyor. .NET icin de eminim cok benzeri vardir.


Bunun yapilmasindaki esas mantik su, repository islemlerini kodun geri kalanindan ayirmak istiyoruz. Al bunu kaydet, bana bunlari getir gibi islemleri DRY ve Solid prensiplerine uygun sekilde yapmamiza olanak sagliyor.

Yine ornegi Java tarafindan vereceğim .NET API'sine hakim olmadigim icin:

Kod:
interface UserRepository extends CrudRepository<User, Long>

interface ProductRepository extends JpaRepository<Product, String>

Ustte hem "user" hem de "product" icin 2 tane Repository interface tanimi yaptim. Bunlar "Repository Pattern" e uygun.

Tanimlamadaki Interface'lere dikkat edersen bir tanesi "CrudRepository" extend ediyor, diger "JpaRepository". Bunlar Framework'un kendisinin yazdigi "Generic Repository" patternine uygun.

Boylece demis oluyorum ki bana bir UserRepository implemente et ve bununla sadece CRUD operasyonlari yapacagim.

Digerinde de daha gelismis ozelliklere sahip JPA repository ozellikleri yapacagim.

JPA Repository si de polimorfik olarak zaten CRUD repository'sinin super-seti.

Karisik gibi gelebilir ama aslinda tum bu islemler ustte yazdigim gibi neredeyse her ORM Class'i icin ortak kullanilan save, Update, delete, page, query vs operasyonlarina ayri ayri kod yazmamak ve projenin geri kalaninda decouple etmek icin yaptığımiz tanimlamalar.

ORM kullaniliyorsa kullanilmali, cunku daha standardize hale getiriyor kodu.

Abi şöyle sanırım anladıgım kadarıyla örneğin bir get yapılacak bu get işlemini belirli bir parametre yerine yapmak yerine o get işlemini yapacağımız Entity'nin herhangi bir Attribute'ı ile get işlemi yapabiliyroruz. Bayağı bir zor ve bilmediğim bir şeymiş. Ayrıca çoğu senior da bu yötnemi kullanıyormuş. Keşke daha erken ögrenseydim canım cok sıkıldı vallahi.
 
Abi şöyle sanırım anladıgım kadarıyla örneğin bir get yapılacak bu get işlemini belirli bir parametre yerine yapmak yerine o get işlemini yapacağımız Entity'nin herhangi bir Attribute'ı ile get işlemi yapabiliyroruz. Bayağı bir zor ve bilmediğim bir şeymiş. Ayrıca çoğu senior da bu yötnemi kullanıyormuş. Keşke daha erken ögrenseydim canım cok sıkıldı vallahi.

Aslinda tam olarak oyle degil. Ornegin senin elinde "User" objesi var. class olarak degil instance olarak var.

var user = new User()

Bu sekilde tanimladin diyelim.
Bu objeyi repository'e paslayarak kaydedilmesini sagliyorsun.

userRepository.save(user)

Aslinda repository pattern'in tam olarak yaptigi sey bu. Oturup da "insert into users " bilmemne diye ugrasmiyorsun. O da zaten arka planda ORM framework'u kullaniyor. Hibernate gibi.

Diyelim ki id'si "3" olan kullaniciyi almak istiyorsun. userRepository.findById(3)
Bu sekilde elinde "user" objesi olusuyor. Bu objeyi senin icin ORM instantiate ediyor.

Senin bahsettigin gibi get yapmak istediginde aslinda "proxy" pattern kullanmis oluyorsun.
"user.getNotebooks()" seklinde bir kullanicinin aldigi notlari listelemek istediginde ORM senin icin ikinci bir istek olusturur, cunku muhtemelen farkli bir tablodan daha data cekmesi gerekecek. Bunu da proxy ile yapar. Yani User objesi aslinda UserProxy objesidir, sen bir attribute'una ulasmak istediginde ORM araya girip istenilen datayi senin icin fetch eder.

Burada orneklendirirken epeyce basite indirgiyorum, cunku bu islemi ACID altinda bir transaction ile yapmak istiyor olabilirsin, user getirilirken ona ait attribute'lar direkt hazir gelsin isteyebilirsin ( EAGER fetching ) ya da herhangi bir sebepten user attribute'larini farkli bir DB de saklamayi dusunebilirsin. Ornegin Eticaret sitelerinde urun bilgileri SQL ve noSQL DB'lerde saklanabilir farkli sebeplerden.

Ama genel konsept hep ayni, copy paste yapmak istemiyoruz ve uygulamadaki data islemleri ile business islemlerini birbirinden ayirmak istiyoruz. Bu hem proje buyudugunde sadelik kazandiriyor hem de test etmeyi cok kolaylastiriyor. Dezavantajlari da var, her zaman ORM kullanmak istemeyebilirsin cunku generate ettigi SQL hic optimal olmuyor bazen ama baslangic icin epey rahatlik saglayacaktir.
 
Aslinda tam olarak oyle degil. Ornegin senin elinde "User" objesi var. Class olarak degil instance olarak var.

var user = new User()

Bu sekilde tanimladin diyelim.
Bu objeyi Repository'e paslayarak kaydedilmesini sagliyorsun.

userRepository.save(user)

Aslinda repository Pattern'in tam olarak yaptigi şey bu. Oturup da "insert into users " bilmemne diye ugrasmiyorsun. O da zaten arka planda ORM Framework'u kullaniyor. Hibernate gibi.

Diyelim ki ID'si "3" olan kullaniciyi almak istiyorsun. userRepository.findById(3)
Bu sekilde elinde "user" objesi olusuyor. Bu objeyi senin icin ORM instantiate ediyor.

Senin bahsettigin gibi get yapmak istediginde aslinda "proxy" pattern kullanmis oluyorsun.
"user.getNotebooks()" seklinde bir kullanicinin aldigi notlari listelemek istediginde ORM senin icin ikinci bir istek olusturur, cunku muhtemelen farkli bir tablodan daha data cekmesi gerekecek. Bunu da proxy ile yapar. Yani User objesi aslinda UserProxy objesidir, sen bir attribute'una ulasmak istediginde ORM araya girip istenilen datayi senin icin fetch eder.

Burada orneklendirirken epeyce basite indirgiyorum, cunku bu islemi ACID altinda bir transaction ile yapmak istiyor olabilirsin, user getirilirken ona ait Attribute'lar direkt hazir gelsin isteyebilirsin ( EAGER fetching ) ya da herhangi bir sebepten user attribute'larini farkli bir dB de saklamayi dusunebilirsin. Ornegin e-ticaret sitelerinde ürün bilgileri SQL ve noSQL DB'lerde saklanabilir farkli sebeplerden.

Ama genel konsept hep ayni, copy paste yapmak istemiyoruz ve uygulamadaki data islemleri ile business islemlerini birbirinden ayirmak istiyoruz. Bu hem proje buyudugunde sadelik kazandiriyor hem de test etmeyi cok kolaylastiriyor. Dezavantajlari da var, her zaman ORM kullanmak istemeyebilirsin cunku generate ettigi SQL hiç optimal olmuyor bazen ama baslangic icin epey rahatlik saglayacaktir.

Abi şeyi biliyorum. Bahsettiğin ORM araçlarından en çok kullandığım EntityFramework Core'da Linq sorguları. Bahettiğin şey burada şu şekilde yapılıyor mesela diyelim ki ID çekeceksin FirstOrDefault var ilişkisel bir şeyler çekeceksin Include var şart koyacaksın where var bunları gayet iyi biliyorum. Şimdi şöyle aslında burada sorduğum şey senin dediğin gibi bir sorgu yapılacağı zaman bu sorgunun tekrar etmemesi için tek bir instance üzerinden alınması. Mesela şöyle bir add Update delete cerate, getById gibi işlemler yapılacak. Sürekli tekrar eden şey ne _userRepository. X. Add(Y) _savechanges return bu kodların aslında cok fazla kez tekrar ettiğin fark etmiştim sonrasında şöyle bir şey düşündüm ya bu kodları kısaltmanın bir yöntemi yok mu? Sonrasında da bugün de böyle bir şeyin varlığını öğrendim fakat yapısı biraz zor ayrıca ben repository patterne alıştığım için interface repository Controller katmanlarımla bu işlemi kolay bir şekilde yapıyordum. Sonrasında bu işlemin yanlış olduğunu öğrendim bakalım yine de ama ögrenmesi gercekten zor. Abi Allah senden razı olsun ne zaman konu açsam tek sen yazıyorsun.
 
Abi şeyi biliyorum. Bahsettiğin ORM araçlarından en çok kullandığım EntityFramework Core'da Linq sorguları. Bahettiğin şey burada şu şekilde yapılıyor mesela diyelim ki ID çekeceksin FirstOrDefault var ilişkisel bir şeyler çekeceksin Include var şart koyacaksın where var bunları gayet iyi biliyorum. Şimdi şöyle aslında burada sorduğum şey senin dediğin gibi bir sorgu yapılacağı zaman bu sorgunun tekrar etmemesi için tek bir instance üzerinden alınması. Mesela şöyle bir add Update delete cerate, getById gibi işlemler yapılacak. Sürekli tekrar eden şey ne _userRepository. X. Add(Y) _savechanges return bu kodların aslında cok fazla kez tekrar ettiğin fark etmiştim sonrasında şöyle bir şey düşündüm ya bu kodları kısaltmanın bir yöntemi yok mu? Sonrasında da bugün de böyle bir şeyin varlığını öğrendim fakat yapısı biraz zor ayrıca ben repository patterne alıştığım için interface repository Controller katmanlarımla bu işlemi kolay bir şekilde yapıyordum. Sonrasında bu işlemin yanlış olduğunu öğrendim bakalım yine de ama ögrenmesi gercekten zor. Abi Allah senden razı olsun ne zaman konu açsam tek sen yazıyorsun.

Rica ederim, malesef ben de C# ve .NET API'ina pek hakim degilim. Ama konsept olarak biliyorum.

Dusundugun sey dogru, bunlari kisaltmanin yolu Generic Repo kullanmak. Generic Repo'nun bir baska avantaji da kodu farkli DB kullanmaya daha uygun hale getirmesi. Ister MySQL e yazarsin, ister Azure bilmem ne DB ye.
 
Rica ederim, malesef ben de C# ve .NET API'ina pek hakim degilim. Ama konsept olarak biliyorum.

Dusundugun sey dogru, bunlari kisaltmanin yolu Generic Repo kullanmak. Generic Repo'nun bir baska avantaji da kodu farkli DB kullanmaya daha uygun hale getirmesi. Ister MySQL e yazarsin, ister Azure bilmem ne DB ye.
Abi peki sana kişisel bir soru sorabilir miyim?
 
Abi şöyle sanırım anladıgım kadarıyla örneğin bir get yapılacak bu get işlemini belirli bir parametre yerine yapmak yerine o get işlemini yapacağımız Entity'nin herhangi bir Attribute'ı ile get işlemi yapabiliyroruz.
Bitwise tam olarak öyle değil demiş ama sizin kastettiğiniz şey mesela User ya da Product gibi entitylerin çeşitli fieldları ile data çekmek ise Spring JPA bunu destekliyor, yani findByProductName, findByProductCode, findByProductCodeAndColor vb. gibi "find..And..." (sorduğunuz sanırım bu) formatının yanı sıra çok daha farklı queryleri (delete, count vs.) ve operatörleri (and, less, greater, after, in... vs.) de generate edebiliyor.

 
Bitwise tam olarak öyle değil demiş ama sizin kastettiğiniz şey mesela User ya da Product gibi entitylerin çeşitli fieldları ile data çekmek ise Spring JPA bunu destekliyor, yani findByProductName, findByProductCode, findByProductCodeAndColor vb. gibi "find..And..." (sorduğunuz sanırım bu) formatının yanı sıra çok daha farklı queryleri (delete, count vs.) ve operatörleri (and, less, greater, after, in... vs.) de generate edebiliyor.


Evet cok dogru.

Benim demek istedigim suydu aslinda, repository uzerinden data cekiliyorsa findBy ya da orderBy gibi bu sorudaki "Repository Pattern" in kapsamina giriyor.

Ancak "user.getAttributes()" seklinde repository'nin kendisinin olusturdugu bir objenin degerlerine erisilmek istendiginde burada "Proxy Pattern" devreye giriyor.

Ben muhtemelen ya sormak istedigini anlamadim ya da cok design pattern merkezli dusunerek cevapladim.
 

Technopat Haberler

Yeni konular

Geri
Yukarı