Generic Repository ve Unit of Work Kullanarak Temel Bir Infrastructure Tasarlamak

Bunlar da hoşunuza gidebilir...

43 Cevaplar

  1. Kaan Can dedi ki:

    Selam, makale çok açıklayıcı olmuş teşekkürler.
    Unit test haricinde web tarafında unit of work’ü kullanmak için yine her controller’ın constructor’ında mı unitofwork’e dbcontext’i tanımlayacağız?

  2. kerem dedi ki:

    Merhabalar,

    Açıklayıcı bir makale. Elinize sağlık. Anlayamadığım kısım IUnitWork içinde tanımlanan GetRepository() generic metodunun ne için tanımlandığı ? Kullanım olarak bir satır ibaresi görünmüyor.

    • Gökhan Gökalp Gökhan Gökalp dedi ki:

      Merhaba, tanımlanan method aslında EFUnitOfWork sınıfını initialize ettikten sonra repository’leri kolaylıkla oluşturabilmek içindi. Örneğin:

      _userRepository = _uow.GetRepository< User >();

      gibi. Açıkcası bu örnek UI kısmına bir MVC projesi hazırlıyordum, fakat vaktim yetmediği için test case’lerinde bu şekilde kalmış. 🙂

      Teşekkürler dikkatiniz için.

  3. Hamza Cakir dedi ki:

    Ellerine saglik. Güzel olmus. Makalen bana bayagi yardimci oldu.

  4. Ahmet Kurt dedi ki:

    Merhaba,

    Yazılarınızı yeni takip etmeye başladım. Bu faydalı konular hakkında bizleri bilgilendirdiğiniz için öncelikle çok teşekkür ediyorum.

    Şöyle bir sorum olacaktı:

    Repository içerisindeki Delete metodunda neden EntityState.Detached kullanmadığınızı öğrenebilir miyim? Sadece bilgi almak için soruyorum. EntityState.Deleted kodunu özellikle mi kullandınız?

    Bir de UnitOfWork içerisindeki Database.SetInitializer(null); kodunun neden kullanıldığını anlayamadım.

    Yanlış anlamayın lütfen sadece bilgi almak ve öğrenmek için soruyorum.

    Yeni yazılarınızı bekliyorum. 😉

    İyi çalışmalar.

    • Gökhan Gökalp Gökhan Gökalp dedi ki:

      Merhaba, öncelikle ben teşekkür ederim.
      İlk soruna gelecek olursak eğer, EntityState’in değişmesinin sebebi; Entityframework kendi içerisinde bir “change tracking” mekanizmasına sahiptir. Kısaca bahsetmem gerekirse eğer, daha önceden çekmiş olduğun entity’lerin state’lerini tutmaktadır üzerinde. Örneğin sadece bir proprety güncelledi isen, bunun update sorgusunda sadece güncellediğin property’leri göndermesi gibidir. Silinme aşamasında ise önce silinip silinmediğini kontrol edip sonrasında context’e attach’leyip siliyoruz. Bu konuyu biraz detaylı google’layabilirsin “change tracking”. Bir diğer sorun ise, SetInitializer kısmında herhangi bir Database initializer kullanmamadır null bırakmam. Orada istersen IDatabaseInitializer interface’inden implemente ettiğin bir sınıf ile initialize edebilirsin veya inbuilt olarak içerisinde bulunan, DropCreateDatabaseAlways veya DropCreateDatabaseIfModelChanges gibi sınıfları kullanabilirsin.

      İyi günler dilerim.

      • Ahmet Kurt dedi ki:

        Vakit ayırıp bilgilendirdiğiniz için çok teşekkür ederim. “change tracking” konusunu araştıracağım.

  5. Ömer Can dedi ki:

    Merhaba, öncelikle makale için teşekkürler. Veri tabanını package manager console’dan Update-Database diyerek oluştururken A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: SQL Network Interfaces, error: 26 – Error Locating Server/Instance Specified) şeklinde bir hata alıyorum sebebi ne olabilir ?

    • Gökhan Gökalp Gökhan Gökalp dedi ki:

      Merhaba, Migration sırasında bu işlemi yapmadan önce, Package Manager’ın Default project kısmında RepveUOW.Data seçili olduğundan emin olun ve, içerisindeki app.config’de bir connection string’in tanımlı olduğundan emin olun.

      • Ömer Can dedi ki:

        Default olarak RepveUOW.Data seçili ve app.config’de connectionString’i tanımladım. Bildiğiniz başka bir sebebi olabilir mi ?

        • Gökhan dedi ki:

          Sağ kısımda solutiondaki RepveUOW.Data class library sağ tıklayıp set as startup project seç sonra buildleyip tekrar dene olur.

  6. Nazmi Altun dedi ki:

    Merhaba Gökhan,

    Güzel makale. Yalnız, IUnitOfWork’de fonksiyon ismi olarak SaveChanges kullanmak, interface’i EntityFramework için yazılmış gibi gösteriyor. Commit daha uygun bir isim olabilirdi. Aynı şekilde interface’de Rollback eksik. Onun haricinde güzel makale, eline sağlık.

  7. Ahmet Kurt dedi ki:

    Merhaba,

    Neden repository içerisinde iki tane Delete metodu kullandınız acaba? Sonuçta her ikisi de aynı amacı gerçekleştirmiyor mu? Çünkü Delete(int id) de Delete(T entity) metodunu çağırıyor.

    GetById metodunu test metodu içerisinden çağırsam ve entity’i elde ettikten sonra sadece Delete(T entity) metodunu kullanarak silme işlemi yapsam olmaz mı?

    Ben sadece Delete(T entity) metodunu kullanmak istiyorum ama yanlış yapmak istemiyorum. Bu yüzden müsait bir vaktinizde sizden bilgi almak istiyorum.

    Şimdiden çok teşekkürler.

    • Gökhan Gökalp Gökhan Gökalp dedi ki:

      Merhaba,
      İstediğiniz method imzasını kullanabilirsiniz Delete işlemi için, bu sadece kullanım kolaylığı için yazılmış bir method imzası. Yeri gelir elinizde sadece entity’nin Id’si olur, yeri gelir sadece entity olur gibi. Kullanımı size kalmış. Bir nevi delete işlemini ilgili developer arkadaşa, tek satırda yapabilme yeteneğini sağlamak diyebiliriz.

  8. Ahmet Kurt dedi ki:

    Tekrar Merhaba,

    Bu konu başlığı altındaki üçüncü sorum olacak, umarım çok rahatsız etmiyorumdur. 🙂

    EFRepository içerisinde id’ye göre exists kontrolü yapmak istiyorum. IEntity adında bir interface ürettim ve içerisinde de “Guid id { get; set; }” tanımladım. Ardından bunu EFRepository’si içerisinde şu şekilde tanımladım:

    “public class EFRepository : IRepository where T : class, IEntity”

    Sonra “public bool Exists(Guid id)” metodunu oluşturdum ve sadece aşağıdaki kodu return ettim:

    “return dbSet.Any(e => e.Id == id);”

    Projeyi build ettiğimde EFUnitOfWork sınıfımda “public IRepository GetRepository() where T : class” metodunda hata aldım. Hata da şu şekilde:

    “The type ‘T’ cannot be used as type parameter ‘T’ in the generic type or method ‘EFRepository’. There is no implicit reference conversion from ‘T’ to ‘SolutionName.Data.Repository.IEntity’.”

    Gün boyunca bu hatayı çözmeye çalıştım. Aslında tek yapmak istediğim id’ye göre exists kontrolü yapmak. Bunu dbSet.Find(id) ile de yapabilirim ama Any ile sadece var/yok bilgisini almak istiyorum. Find bana komple kaydı döndürecek. Bana performans açısından daha etkili bir şey gerekiyor. Bunun da Any olacağını düşündüm.

    Bunu en etkin şekilde nasıl yapabilirim acaba? Tavsiyeleriniz benim için çok önemli.

    Teşekkürler.

    • Halit Yurttaş dedi ki:

      Where T konusunda hata alan arkadaş T nerede sınıfa geçiyor, yani T yi sınıfla özdeştirmemişsin. Class ın veya class ın interfacelerinden birinin template ine T yi geçirmen gerek. Yani class efrepo gibi

  9. kamil ocak dedi ki:

    Merhaba hocam,
    Benim iki farklı sorum olacak.

    1- Migrations kısmını enable etmek şart mıdır? Örneğin biz entityframework ile sunucuda çalışan bir veritabanı ile çalışıyorsak nasıl bir yol izlemeliyiz?

    2- UnitOfWork bize ne gibi yarar sağladı bu projede net bir şekilde göremedim. Olmasaydı ne olurdu mesela?

    • Gökhan Gökalp Gökhan Gökalp dedi ki:

      Merhabalar,

      1) Öncelikle ef ile sunucuda çalışan bir veritabanı ile çalışıyorsak kısmını tam anlayamadım. Zaten olması gereken değil mi? Buradaki migrations sorunuz sizin yaklaşımınız ile ilgili açıkcası. Code-first, model-first, db-first vb. Code-first gidiyorsanız ve entity modelinizin db deki tablonuzu tamamen prezente etmesini istiyorsanız (herhangi bir değişim karşısında) migration’ı enable etmelisiniz.
      2) UnitOfWork genelde transaction’ları yönetmekte kullanabilirsiniz. Tabi transactional bir işlem gerçekleştiriyorsanız business case’lreinizde. Bunlar dışında zaten EF kendi içerisinde bir uow barındırıyor. Faydasını bu case’de görememenizin sebebi ise belkide test case’lerini biraz daha açmalıydım. Örneğin add user örneğinde sadece user oluşturup en son _uow.SaveChanges(); diyerek ekletmek yerine, bir kaç farklı işlem daha gerçekleştirip tek bir pipe üzerinden _uow.SaveChanges(); dersek daha anlamlı olabilirdi…

      Saygılar.

  10. Gürkan dedi ki:

    öncelikle yazınız için çok teşekkür ederim. işimi fazlası ile gördü. fakat karşılaştığım bir durum var. bir projede Repository Class’ı abstract olarak tanımlı. ( public abstract class Repository : Irepository where T : class )
    ben unit’Test de
    private IUnitOfWork _uow
    private Irepository _tabloAdiRepository; olarak tanımlayıp

    TestInitialize methodunda ise
    _tabloAdiRepository= new Repository(_dbContext);

    yazdığımda hata alıyorum. abstract class’lar için kullanımı hakkında bilgi verirseniz çok iyi olur. iyi günler.

    • Gökhan Gökalp Gökhan Gökalp dedi ki:

      Merhaba, ilgili repository class’ınızın bir concrete repository’si olmalıdır. Zaten _tabloAdiRepository = new Repository diyerek hangi reposiyory olduğunu dbContext üzerinden resolve edemezsiniz. Abstraction üzerinden gitmelisiniz. Saygılar.

  11. hakan dedi ki:

    Çok güzel bir yazı olmuş.
    orcle içinde geçerli bir infrastructure olabilir mi?Değişiklik nerelerde yapılmalı?
    Teşekkürler.

  12. hakan dedi ki:

    Cevap için Teşekkürler Gökhan Bey,
    ikinci bir sorumda şu;
    Denemeden sormak istiyorum.İstediğim mimari “db first” ,
    Model katmanını ve Migration ‘ı kaldırıp.
    Model katmanında edmx dosyamızı tutmamız yeterli olur mu?
    n tier yapıda db first mimariye sahip bir infrastructure bulamadım.
    i

  13. özgür dedi ki:

    Merhaba,
    UnitOfwork un içierinde GetRepository tam olarak ne işe yarıyor kafama takıldı, örnekleyebilir misiniz?
    bu arada makale güzel olmuş elinize sağlık.

    • özgür dedi ki:

      _uow = new UnitOfWork();
      repo = _uow.GetRepository();

      aslında business katmanı olarak nasıl inşa edebiliriz.

    • Gökhan Gökalp Gökhan Gökalp dedi ki:

      Merhaba, tanımlanan method aslında EFUnitOfWork sınıfını initialize ettikten sonra repository’leri kolaylıkla oluşturabilmek içindi. Örneğin:
      _userRepository = _uow.GetRepository();

  14. Rec dedi ki:

    Elinize sağlık çok yararlı makale Tam isabet olmuş eğitim videoları çekmeyi düşündünuzmu hic. Çünkü Türkçe kaynak bulmakta çok zorlanıyoruz.

  15. Recep dedi ki:

    Merhaba dbcontext sürekli null geliyor mvc projesinde kullanmak istediğimde acaba değerlendir vaktiniz varmı. sayğılar.

  16. Recep dedi ki:

    Merhaba class a özel olarak ekleyemedim bir türlü yada uyarlayamadım;

    IQueryable Etiketler(string[] etiketler);
    void EtiketEkle(int IlanId, string Etiket);
    void IlanEtiketEkle(int IlanId, string[] etiketler);

    public void EtiketEkle(int IlanId, string Etiket)
    {
    if (Etiket != null && Etiket != string.Empty)
    {
    string[] Etikets = Etiket.Split(‘,’);
    foreach (var tag in Etikets)
    {
    Etiket etiket = this.Get(x=> x.EtiketAdi.ToLower() == tag.ToLower().Trim());
    if (etiket == null)
    {
    etiket = new Etiket();
    etiket.EtiketAdi = tag;
    Insert(etiket);
    Save();
    }
    }
    IlanEtiketEkle(IlanId, Etikets);
    }
    }

    public void IlanEtiketEkle(int IlanId, string[] etiketler)
    {
    var ilan = _context.Ilanlar.FirstOrDefault(x => x.Id == IlanId);
    var gelenetiket = this.Etiketler(etiketler);
    ilan.Etiket.Clear();
    gelenetiket.ToList().ForEach(etiket => ilan.Etiket.Add(etiket));
    }

    public IQueryable Etiketler(string[] etiketler)
    {
    return _context.Etiketler.Where(x => etiketler.Contains(x.EtiketAdi));
    }

    çok uğraştım ama interface tamam ama repository class a uyarlayamadım.

  17. Metin dedi ki:

    Tam aradığım gibi bir kaynak oldu bu teşekkürler.

  18. Ahmet Refik dedi ki:

    makalenin kendisi inanılmaz yorumlar ve cevapları ise tadından yenmiyor.

  19. Yunus dedi ki:

    Merhaba bu güzel makale için teşekkür ederim.
    Birkaç sorum olacak.

    1-Kitabınızdaki örnek projede UnitOfWork kullanmamıştınız. SaveChagnes metodu RepositoryBase sınıfının içerisinde bulunuyordu. Bu konuda “Best Practices” hangisi ? (Makalenizdeki yapı mı yoksa kitaptaki yapı mı? )

    2-Yine kitabınızda her entity için ayrı bir Repository arayüzü oluşturmuştunuz. Burada ise generic parametre alan genel bir IRepository arayüzü görüyorum. Yine ilk sorudaki gibi “Best Practices” hangisi?

    3-Kitabınızdaki projeye mock objelerle unit test uygulamak istiyorum. Hangi nesneyi mocklamamı önerirsiniz Repository’leri mi yoksa Context nesnesini mi ?

    • Gökhan Gökalp Gökhan Gökalp dedi ki:

      Merhaba,

      Öncelikle teşekkür ederim yorumunuz için.

      1) Herhangi bir best practice öneremeyeceğim bu konuda. Tamamen domain modelinizin ihtiyaçlarına göre değişebilmekte kuracağınız yapı.
      2) Eğer video izlediyseniz, her entity için bir repository oluşturmamalıyız, domain modelimize göre oluşturmalıyız diye belirtmiştim. Generic olarak üretmek, implementasyonda diğer domain modeller için başka bir repository interface’i oluşturulamayacağı anlamına gelmez. IRepository interface’ini implemente eden sınıfın, farklı ihtiyaçlarına göre IFooRepository interface’i daha tanımlanabilir ve implemente edilebilir. Buda ihtiyaçlarınıza göre şekillenmektedir.
      3) Bu konuda buraya bir göz atmanızı tavsiye edebilirim. Context mock’lamak için benimde kullandığım bir kütüphanedir. https://blog.goyello.com/2016/07/14/save-time-mocking-use-your-real-entity-framework-dbcontext-in-unit-tests/

Bir Cevap Yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

*