Entity Framework - Generic Repository ve Unit of Work Uyarlaması

thinkingMerhaba Arkadaşlar,

Yazılım dünyasında var olan mimari prensipler veya tasarım kalıpları tek başlarına belirli sorunları çözseler de, bazı kurumsal projelerde mutlak suretle bir arada düşünülmeleri gerekir. Söz gelimi Repository ve Unit of Work kalıpları, özellikle Domain Driven Design odaklı yapılarda bir arada değerlendirilmesi gerekenlerdendir.

DDD denilince aklımıza daha çok veri odaklı uygulamalar gelir ve bu tip ürünlerde RDBMS(Relational Database Management System) lerin yeri hatırı sayılır ölçüde fazladır(Her ne kadar son yıllarda NoSQL cephesinde önemli gelişmeler ve kullanımda ciddi artışlar olsa da…)

Hal böyle olunca O/RM(Object Relational Mapping) araçlarının kullanımı da önem kazanmaktadır. Yıllardır hayatımızda olan bu araçlar modellerin nesnel olarak inşasında da önemli bir yere sahiptirler. Lakin Object Oriented dünyasının kuralları içerisinde yaşarlar ve bu yüzden bazı kurumsal prensipleri uygulamaları gerekmektedir.

Benim gibi .Net üzerinde geliştirme yapanlar için O/RM araçları da az çok bellidir. Entity Framework bunlardan birisidir. Ancak Entity Framework’ ün uygulamalardaki kullanımında genellikle hatalar yapılır. Enterprise bir çözüm söz konusu olduğunda varsayılan olarak Data Access ve Business Logic katmanlarının olması izolasyon açısından önemlidir. İşte bu noktada DAL ve BLL arasındaki kullanımlarda EF’in çoğu zaman bir O/RM aracı olarak soyutlanamadığı görülür. Hal böyle olunca sistemin farklı bir kaynağı kullanarak yaşamaya devam etmesi de zorlaşır.  Repository ve Unit of Work özellikle bu vakalara çözüm niteliğindeki iki değerli desendir.

Hiç kimse bu deseneleri Martin Fowler kadar iyi açıklayamaz. Bu yüzden makalenin amacı ilgili desenelerin Entity Framework için örnek bir kullanımının anlatımından ibarettir.

İşin Gerçeği

Gerçek hayatta Entity Framework veya başka bir O/RM aracının kullanıldığı hallerde aşağıdaki grafikteki iki durumdan birisi söz konusu olur(Genellikle de en soldaki). Klasik olarak DbContext doğrudan iş katmanında değerlendirilir. Ancak Test Driven Development veya Domain Driven Design gibi yaklaşımların kullanıldığı geliştirme süreçlerinde, Repository ve Unit of Work desenelerinin icra edilmesi önemlidir. Nitekim bu sayede uygulamanın iş mantığının tutulduğu katman ile veri erişim katmanının izole edilmesi kolaylaşır. t anında farklı bir Repository ile çalışılabilmesi veya yenilerinin yazılarak sisteme dahil edilmesinin yolu açılır. Aynı kolaylık Unit of Work yapıları için de geçerlidir.

ruof_1

İlk senaryoya göre iş mantığı, veri erişimi ve EF arasında kuvvetli bağlar oluşur. Bu sebepten, üründe kullanılan veri tabanını değiştirmek(farklı bir Repository’ yi tercih etmek) ve özellikle Unit Test gibi yapılarda Mock nesneleri değerledirmek zorlaşır. Bir Unit Test metodu içerisindeki işlemler bütününde her zaman CRUD(CreateReadUpdateDelete) operasyonları icra edilmek istenmeyebilir. Nitekim iş bütününün Repository odaklı olmayan kısımlarının test edilmesi de söz konusudur.

Unit Test’ lerin çalıştığı geliştirme ortamının hiç bir şekilde bir veri kaynağına gidemediği hallerde geri kalan kısmın test edilme ihtiyacı bu tip bir gereksinimdir. Ayrıca aynı veri kaynağı ile çalışılacak diye bir kural yoktur. Domain içerisindeki Entity modelleri sabit kalabilir ve iş kuralları çok az değişiklik gösterebilir. Ama verilerin yazıldığı ortamlar duruma göre farklılık gösterebilir, açılıp kapatılmak istenebilir. Bu sebeple soyutlama(abstraction) yapmak ve uygun sözleşme tanımlamalarını(Interface bildirimleri diyebiliriz) işin içerisine katmak önemlidir.

Gelin konuyu basit ve pek de işe yaramayacak örnek bir senaryo üzerinden ele alalım. Amacımız içinde iki Entity barındıran bir DbContext türevini, Repository ve Unit of Work desenleri çerçevesinde nasıl ele alabileceğimizi incelemektir.

Code First ile Entity Modelin İnşası

Örnek uygulama her zaman ki gibi gösterişsiz bir Console projesidir. Amaç ilgili desenlerin sade bir uyarlamasını görebilmektir. Ama öncesinde NuGet üzerinden güncel Entity Framework’ ün son sürümü projeye indirilerek işe başlanabilir.

rpuow_1

Ardından kobay olarak aşağıdaki Entity sınıfları ve DbContext türevini yazabiliriz.

ruof_2

using System.Collections.Generic; 
using System.Data.Entity;

namespace RPandUOW.EntityModel 
{ 
    public class ShopContext 
        : DbContext 
    { 
        public DbSet<Category> Categories { get; set; } 
        public DbSet<Product> Products { get; set; } 
    } 
    public class Category 
    { 
        public int CategoryID { get; set; } 
        public string Title { get; set; } 
        public virtual ICollection<Product> Products { get; set; } 
    } 
    public class Product 
    { 
        public int ProductID { get; set; } 
        public string Title { get; set; } 
        public decimal UnitPrice { get; set; } 
        public int Quantity { get; set; } 
        public int CategoryID { get; set; } 
        public virtual Category Category { get; set; } 
    } 
}

Tipik olarak one-to-many ilişki içerisinde sayabileceğimiz iki POCO tipi bulunmaktadır. Bir kategori ve bu kategoriye bağlı olan ürünler. Gelelim Repository deseninin uygulanış biçimine.

Repository Yapısının İnşası

Öyle bir yapı kurgulamalıyız ki, hem bir Repository için gerekli minimum fonksiyonelliklerin bir sözleşmesi hem de Context içerisinde yer alan her T tipi için çalışabilecek generic bir sınıf olsun. Ve pek tabi varsayılan kuralları istediği gibi işleyecek yeni Repository’ leri yazmanın da yolu açılabilsin. İlk olarak aşağıdaki sınıf diagramında görülen tiplerin tasarlanmasıyla işe başlanabilir.

rpuow_2

ve kodlar;

using RPandUOW.EntityModel; 
using System; 
using System.Collections.Generic; 
using System.Data.Entity; 
using System.Linq; 
using System.Linq.Expressions;

namespace RPandUOW.Repositories 
{ 
    public interface IGenericRepository<T> 
        where T:class 
    { 
        T FindById(object EntityId); 
        IEnumerable<T> Select(Expression<Func<T, bool>> Filter = null); 
        void Insert(T Entity); 
        void Update(T Entity); 
        void Delete(object EntityId); 
        void Delete(T Entity); 
    }

    public class ShopRepository<T> 
        :IGenericRepository<T> 
        where T:class 
    { 
        private ShopContext _context; 
        private DbSet<T> _dbSet; 
        public ShopRepository(ShopContext Context) 
        { 
            _context = Context; 
           _dbSet = _context.Set<T>(); 
        } 
        public virtual T FindById(object EntityId) 
        { 
            return _dbSet.Find(EntityId); 
        } 
        public virtual IEnumerable<T> Select(Expression<Func<T, bool>> Filter = null) 
        { 
            if (Filter != null) 
            { 
                return _dbSet.Where(Filter); 
            } 
            return _dbSet; 
        } 
        public virtual void Insert(T entity) 
        { 
            _dbSet.Add(entity); 
        } 
        public virtual void Update(T entityToUpdate) 
        { 
            _dbSet.Attach(entityToUpdate); 
            _context.Entry(entityToUpdate).State = EntityState.Modified; 
        } 
        public virtual void Delete(object EntityId) 
        { 
            T entityToDelete = _dbSet.Find(EntityId); 
           Delete(entityToDelete); 
        } 
        public virtual void Delete(T Entity) 
        { 
            if (_context.Entry(Entity).State == EntityState.Detached) //Concurrency için 
            { 
                _dbSet.Attach(Entity); 
            } 
            _dbSet.Remove(Entity); 
        } 
    } 
}

Burada neler yaptık, ortalığı nasıl karıştırdık incelemeye çalışalım. IRepository<T> arayüzü içerisinde bir Repository için söz konusu olabilecek temel fonksiyonların tanımlandığını görmekteyiz. CRUD(CreateReadUpdateDelete) operasyonları olarak adlandırabileceğimiz metodlar ile bir Repository’ nin minimumda sahip olması gereken sözleşmeyi de tanımlamış oluyoruz.

ShopRepository<T> sınıfı dikkat edileceği üzere IRepository<T> arayüzünü uygulamakta ve kendi içerisinde DbContext sınıfından türetilmiş bir ShopContext örneğini kullanmaktadır. Yani ShopRepository generic sınıfı, ShopContext içinde tanımlı herhangi bir T tipini kullanarak CRUD operasyonlarını gerçekleştirebilir. Bunun bir diğer anlamıda, farklı kaynakları kullanan veya Mock nesne olabilen Repository tiplerinin istenildiği zaman sisteme dahil edilebilmesidir. Tek yapılması gereken ilgili IRepository<T> sözleşmesinin yeni Repository için uygulanmasından başka bir şey değildir.

Repository’ nin kullandığı Context nesnesinin oluşturulması aslında yapıcı metod içerisinde icra edilmektedir. Burada da generic bir kullanım yolu düşünülebilir. Dikkat çekici noktalardan bir tanese bir Context için söz konusu olan Save işleminin bu tiplerde her angi bir biçimde ele alınmamış olmasıdır. Aslında bu, Unit of Work yapısının inşasında ele alınması gereken bir fonksiyonelliktir. Öyleyse Unit of Work yapısını tesis etmeye başlayabiliriz.

Unit of Work Yapısının İnşası

Entity Framework açısından bir birimlik işi; içerisinde konuya dahil olması gereken Repository örneklerinin oluşturulması ve Save işleminin icra edilmesi olarak düşünebiliriz(Hatta bu yapı içerisine Transaction açılıp kapatılması da dahil edilebilir) Pek tabi Unit of Work yapısınında bir sözleşme üzerinden değerlendirilmesi, farklı Unit of Work’ lerin de değerlendirilebilmesi açısından önemlidir. Bu düşünceler ışığında aşağıdaki yapıyı kurgulayabiliriz.

rpuow_3

ve kodlar;

using RPandUOW.EntityModel; 
using RPandUOW.Repositories; 
using System; 
using System.Transactions;

namespace RPandUOW.UnitOfWorks 
{ 
    public interface IUnitOfWork 
        :IDisposable 
    {   
        void Save(); 
        // Başka operasyonlar da tanımlanabilir. 
        // void OpenTransaction(); 
        // void CloseTransaction(); 
        // gibi 
    }

    public class ShopUnitOfWork 
        :IUnitOfWork 
    { 
        private ShopContext _context = new ShopContext(); 
        private ShopRepository<Category> _categoryRepository; 
        private ShopRepository<Product> _productRepository; 
        private bool _disposed = false; 
        public ShopRepository<Category> CategoryRepository 
        { 
            get 
            { 
                if (_categoryRepository == null) 
                   _categoryRepository = new ShopRepository<Category>(_context); 
                return _categoryRepository; 
            } 
        } 
        public ShopRepository<Product> ProductRepository 
        { 
            get 
            { 
                if (_productRepository == null) 
                    _productRepository = new ShopRepository<Product>(_context); 
                return _productRepository; 
            } 
        } 
        public void Save() 
        { 
            using (TransactionScope tScope = new TransactionScope()) 
           { 
                _context.SaveChanges(); 
                tScope.Complete(); 
            } 
        } 
        protected virtual void Dispose(bool disposing) 
        { 
            if (!this._disposed) 
            { 
                if (disposing) 
                { 
                    _context.Dispose(); 
                } 
            } 
            this._disposed = true; 
        } 
        public void Dispose() 
        { 
            Dispose(true); 
            GC.SuppressFinalize(this); 
        } 
    } 
}

Pek tabi soyutlama amacıyla IUnitOfWork isimli bir arayüz tanımlanarak işe başlanmıştır. Arayüz şu an için Save metodunun uygulanması gerektiğini belirtir. Tabi bir de IDisposable arayüzü nedeniyle Dispose metodunun ezilmesi zorunlıdır. Bir birimlik iş için ihtiyaca göre başka genel fonksiyonellikler de sözleşme içerisine dahil edilebilir. Örneğin bir Transaction açılması ve kapatılması için gerekli metodlar sözleşme ile zorunlu tutulabilir. Tabi bunu çok da spesifik düşünmemek gerekir. Nitekim kimi Repository’ lerin, kullandığı veri kaynakları bir Transaction ile çalışmak zorunda olmayabilir. Hatta ortada bir veri kaynağı da bulunmayabilir(Burada Mock nesnelere atıfta bulunmaktayım)

ShopContext için kullanılacak Unif of Work kurgusunda ise, işe dahil olacak Repository’ ler birer Property olarak tanımlanmış ve sadece okunabilir şekilde son kullanıcıya sunulmuşlardır. Üretim işlemleri sırasında yapılan null kontrolü, Unit of Work nesnesinin yaşamı boyunca, tüm Repository’ lerin aynı Context tipini(ki örnekte _context isimli ShopContext örneğidir) kullanması açısında önemlidir. (Bu durumu daha iyi anlamak için debug modda çalışmanızı öneririm)

Bir başka deyişle örneğin Save işlemi sırasında tüm Repository nesnelerinin aynı DbContext örneği üzerinden işlemlerini gerçekleştirmesi ve tek bir Transaction bütünlüğü içerisinde çalışması sağlanmış olmaktadır. Zaten Unit of Work desenin temel amaçlarından birisi de bu işlem bütünlüğünü kurgulamaktr.

Basit Bir Kullanım

Yazılan Unit of Work uyarlamasının uygulanış biçimi oldukça kolaydır. Normal şartlarda bir BLL fonksiyonelliği içerisinde de değerlendirilebilir. Konunun basitçe ele alınması açısından Main metodu aşağıdaki kodları içerecek şekilde geliştirilmiştir.

using RPandUOW.EntityModel; 
using RPandUOW.UnitOfWorks; 
using System; 
using System.Collections.Generic;

namespace RPandUOW 
{ 
    class Program 
    { 
        static void Main(string[] args) 
        { 
            using (ShopUnitOfWork worker = new ShopUnitOfWork()) 
            { 
                Category computerBook = new Category { Title = "Computer Books" }; 
                worker.CategoryRepository.Insert(computerBook); 
                computerBook.Products = new List<Product> { 
                    new Product { Title = "Advanced NoSQL", Quantity = 1, UnitPrice = 34.59M }, 
                    new Product { Title = "NHibernate in Action", Quantity = 5, UnitPrice = 29.99M }, 
                    new Product { Title = "Unleashed Delphi 2.0", Quantity = 3, UnitPrice = 9.99M } 
                }; 
                Category cookBook = new Category { Title = "Cook Books" }; 
                worker.CategoryRepository.Insert(cookBook); 
                cookBook.Products = new List<Product> { 
                new Product() 
                    { 
                        Title = "Italian Kitchen", Quantity = 20, UnitPrice = 12 } 
                    }; 
                worker.CategoryRepository.Insert(cookBook); 
                worker.Save(); 
                var books = worker.ProductRepository.Select(p => p.CategoryID == computerBook.CategoryID); 
                foreach (var book in books) 
                { 
                    Console.WriteLine("{0} {1} {2}", book.Title, book.UnitPrice, book.Quantity); 
                } 
            } 
        } 
    } 
}

rpuow_4

IDisposable arayüzü implementasyonu nedeniyle ShopUnitOfWork sınıfı using bloğun içerisinde kullanılabilir. Zaten dipose işlemi sınıfın içerisinde override edilmiştir. Blok içerisinde bir dizi örnek işlem icra edilmektedir. Buna göre bir kaç kategorinin ve bu kategorilere bağlı ürünlerin eklenmesi işlemi ele alınmaktadır. Save işlemi, Unit of Work uyarlamasının bir fonksiyonu olduğundan, dahil edilen tüm Repository örnekleri için ortak bir kullanım noktasıdır. Öyle ki, örnekte asıl Context nesnesi üzerinden yapılan kaydetme işleminin bir TransactionScope içerisinde gerçekleştirilmesi sağlanmaktadır.

Görüldüğü üzere Repository ve Unit of Work desenelerini Entity Framework tarafında uygulamak oldukça kolaydır. Kaynaklarda bu desenlerin daha etkili uygulanış biçimlerini de görebilirsiniz. Örneğin Codeplex’ in şu adresindeki uygulanış tarzı beni etkileyenler arasındadır. Hatta Unit of Work uyarlamasının daha generic ve Context’ lere gevşek bağlı(Loosely Coupled) olan bir versiyonu da yazılabilir(İşin içine Dependency Injection da katılıp olay daha bir renkli hale getirilebilir) Bunlara biraz kafa yormakta fayda vardır. 

Böylece geldik bir makalemizin daha sonuna. Tekrardan görüşünceye dek hepinize mutlu günler dilerim.

Yorumlar (23) -

  • Elleriniz dert görmesin çok güzel bir anlatım olmuş
  • Çok güzel anlatmışsınız teşekkürler. Bir sorum olacak. İki ayrı unit of work ün tek transactionda çalışması gibi bir şey söz konusu değildir sanırım. Eğer tek transaction istiyorsak bu iş için ayrı bir unit of work mü tanımlanmalı. Tekrar teşekkürler.
    • Öncelikle değerli geri dönüşünüz için teşekkür ediyorum. Bence mümkün olabilir. Daha yukarıdan bakarsak, n sayıda Unit of Work' ün bir Flow içerisinde State Machine veya Sequential tarzında dizildiği bir durum düşünülebilir belki. Yani bu iş birimlerini bir akışın parçası olacak şekilde birleştirebiliriz belki de. Hatta bir ESB'nin içinde bile servis şeklinde kendilerine yer bulabilirler. Tabi n sayıda Unit of Work' ün bir arada kullanılması ile ilişkili bir Pattern var mıdır tam bilemiyorum. Bunu araştırmakta yarar var ;)
  • Öyle bir şey yapalım ki; hem Create, Update, Delete işlemlerini, hem de tüm Read işlemlerini tek bir repository üzerinden halledelim. Read işlemlerini tek generic repository üzerinden yaparken istediğimde GetById, istediğimde GetByName, istediğimde, published = true, featured = false gibi filtreleme yapabileym.

    Buradaki arkadaşgüzel bişiler yapmış ama Create, Update falan nasıl yapılıyor çözemedim.

    Zaten bu Genericler, Repositoryler, Unit Of Workler falan kafamı iyice karıştırdı.

    Tüm veritabanı işlemlerimizi tek bir repository üzerinden yapamıyor muyuz?
  • Hocam emeğinize sağlık. Gerçekten anlatımlarınız çok sade ve anlaşılır. Türkçe kaynak sıkıntısı çekilen bir alanda sizin gibilerin katkılarıyla gerçekten güzel birikimler elde edilebilir. Bu sektörde Türkiye'de ciddi bilgi birikime sahip hocalarımız ve uzmanlarımız var. Fakat bilgi paylaşımı gerçekten istenilen ölçüde değil. Önemli olan az bilginin bile paylaşılıp insanların bundan faydalanması. Çalışmalarınız için teşekkürler.
  • EF'nin kendisi unit of work desenini destekliyor bence orm frameworkler ile uow kullanılacaksa standart bir arayüz ile Nhibernate ve Ef gibi frameworkler kullanılabilir ne dersiniz.
  • Öncelikle teşekkürler çok güzel bir yazı olmuş.

    Benim sormak istediğim bir soru var. Veri katmanında her entity için ortak olan CRUD işlemlerim var. Bu işlemleri bu yapı ile çok güzel bir şekilde gerçekleştirebiliyorum. Fakat joinlerimin olduğu biraz daha karmaşık ve daha özel olan işlemleri nereye ve nasıl yazmalıyım? Bu konuda olması gereken yapı hakkında kısaca cevap verebilir misiniz?

    Teşekkürler
  • can
    Merhaba Unit Of Work  yanına service layer katmanına ihtiyaç var mıdır? Varsa nasıl kullanılır.
  • can
    Başka örneklerde Repository kısımında UnitOfWork kısımını injection yapmışlar örnek;
    public class TestRepository<TEntity>:ITestRepository<TEntity>,, IQueryable
            where TEntity : class
    {
      ....
       public TestRepository(IObjectSetFactory objectSetFactory, IUnitOfWork unitOfWork)
    {
       ....
    }
    ...
    }
    burada repository kısımında unitofwork çağırılmış. Sizin verdiğiniz örnekte Unit of work kısımında repository çağırılmış  bunun sıralaması nasıl?

    UnitOfWork->Repository->DbContext ?
    bir de service layer katmanı işin içine girince
    ServiceLayer ->UnitOfWork -> Repository -> DbContext ?
  • Öncelikle makale için tebrikler güzel bir yazı olmuş. Bir kaç sorum olacak: Burada Unitofwork sınıfı da generic olsa daha iyi olmaz mıydı? Bir Ioc container ile interfacelerin inject edildiği bir yapı daha esnek bir yapı oluşturmaz mıydı?
    Teşekkürler.
  • c.p
    public virtual void Update(T entityToUpdate)
            {
                _dbSet.Attach(entityToUpdate);
                _context.Entry(entityToUpdate).State = EntityState.Modified;
            }
    iyi bir paylaşım ama update metodu çalışmaz...
    bir şeyi update etmek demek değiştirmek demek sanırım.
    gelen nesneyi attach etmek demek bu nesne datacontextim dışında turetildi ama datacontextte var oldugundan eminim demek ki bu durumda değişerek gelen bu nesne datacontextteki ile eşleşemez ve hata verir.Eşleşiyorsada değiştirmeye gerek kalmaz. Yni metod gereksiz metod konumuna düşer..
    Son olarak UnitOfWork propertileri modele gore servis dönderiyorlar.
    Oysa UnitOfWork ayrıca sadece get bloklarından oluşan bir IUnitOfWork arayüzünden türeyebilir ve IUnitOfWork klası sadece return edeceği propertilerinde model base servis donderiyor olabilirdi.. Hatta bu model base servislerde kendileri için olan arayüzden türeyip daha kontrollü hale gelebilirlerdi...özet örnek eksiklerle dolu...
    • Evet update metodu hata veriyor. Context içerisinde bu id li kayıt var deniyor. Acaba çözümü nasıl
  • Hocam öncelikle çok teşekkürler çok yararlı bir makale.

    Bir sorum olcak ; Delete komutunu insert ve select te olduğu gibi çalıştırmak isterken
    " System.Data.Entity.Infrastructure.DbUpdateConcurrencyException " hatası aldım. Acaba Delete kullanımı ile ilgili bir örner verebilir misiniz ?
    • Kardeşim hatayı nasıl hallettiğini hatırlıyor musun?
  • Öncelikle emeğinize sağlık.
    Ben generic repository ve unit of work paternlerini wcf application servisinde kullanmak istiyorum ama servis contract ın generic yaptıgımda bilinmeyen type hatasından dolayı servisi generic yapamıyorum. nasıl bir yol izlemeyim tesekkurler
    • Contract' ları uygulayan svc' lerini sadece sunum olarak kullanmalısın, yapmak istediklerini ise farklı katmanlara bölmelisin.
  • iyi çalışmalar makale için teşekkür ederim ama bir sorum olacak.
    160 adet class ı olan bir programım var bunu repository ve interface leri 320 adet yapıyor
    class lar için olan repository lerin generic olan bir metodu var mıdır acaba.

    teşekkürler.
    • ben bu sıkıntı sql query'de procedure oluşturarak çözdüm.Belki faydası dokunur sizlere.
      ALTER PROC [dbo].[ORMCreate2]
      AS
      IF(ISNULL(OBJECT_ID('tempdb..#TBLF8941390E'),0)!=0) BEGIN DROP TABLE #TBLF8941390E END
      CREATE TABLE #TBLF8941390E(Id INT IDENTITY(1,1),Deger NVARCHAR(400))
      INSERT INTO #TBLF8941390E SELECT 'public new void Dispose()'
      INSERT INTO #TBLF8941390E SELECT '{'
      INSERT INTO #TBLF8941390E SELECT 'base.Dispose();'
      INSERT INTO #TBLF8941390E SELECT 'GC.SuppressFinalize(this);'
      INSERT INTO #TBLF8941390E SELECT '}'
      DECLARE @NAME NVARCHAR(400)
      DECLARE DB_CURSOR CURSOR FOR  
      SELECT C.[name] FROM sys.tables AS C WHERE C.name!='sysdiagrams' ORDER BY C.[name]
      OPEN DB_CURSOR
      FETCH NEXT FROM DB_CURSOR INTO @NAME
      WHILE @@FETCH_STATUS = 0
      BEGIN
      INSERT INTO #TBLF8941390E SELECT CONCAT('private ORMRepository<',@NAME,', mdl',DB_NAME(),'> _',(CASE WHEN LOWER(SUBSTRING(@NAME,1,1))='ı' THEN 'i' ELSE LOWER(SUBSTRING(@NAME,1,1)) END),SUBSTRING(@NAME,2,LEN(@NAME)-1),'Repository;')
      FETCH NEXT FROM DB_CURSOR INTO @NAME
      END  
      CLOSE DB_CURSOR  
      DEALLOCATE DB_CURSOR

      DECLARE DB_CURSOR2 CURSOR FOR  
      SELECT C.[name] FROM sys.tables AS C WHERE C.name!='sysdiagrams' ORDER BY C.[name]
      OPEN DB_CURSOR2
      FETCH NEXT FROM DB_CURSOR2 INTO @NAME
      WHILE @@FETCH_STATUS = 0
      BEGIN
      INSERT INTO #TBLF8941390E SELECT CONCAT('public ORMRepository<',@NAME,', mdl',DB_NAME(),'> ',@NAME,'Repository')
      INSERT INTO #TBLF8941390E SELECT '{'
      INSERT INTO #TBLF8941390E SELECT 'get'
      INSERT INTO #TBLF8941390E SELECT '{'
      INSERT INTO #TBLF8941390E SELECT CONCAT('if(_',(CASE WHEN LOWER(SUBSTRING(@NAME,1,1))='ı' THEN 'i' ELSE LOWER(SUBSTRING(@NAME,1,1)) END),SUBSTRING(@NAME,2,LEN(@NAME)-1),'Repository.IsNull())')
      INSERT INTO #TBLF8941390E SELECT '{'
      INSERT INTO #TBLF8941390E SELECT CONCAT('_',(CASE WHEN LOWER(SUBSTRING(@NAME,1,1))='ı' THEN 'i' ELSE LOWER(SUBSTRING(@NAME,1,1)) END),SUBSTRING(@NAME,2,LEN(@NAME)-1),'Repository = new ORMRepository<',@Name,', mdl',DB_NAME(),'>(Context);')
      INSERT INTO #TBLF8941390E SELECT '}'
      INSERT INTO #TBLF8941390E SELECT CONCAT('return _',(CASE WHEN LOWER(SUBSTRING(@NAME,1,1))='ı' THEN 'i' ELSE LOWER(SUBSTRING(@NAME,1,1)) END),SUBSTRING(@NAME,2,LEN(@NAME)-1),'Repository;')
      INSERT INTO #TBLF8941390E SELECT '}'
      INSERT INTO #TBLF8941390E SELECT '}'
      FETCH NEXT FROM DB_CURSOR2 INTO @NAME
      END  
      CLOSE DB_CURSOR2  
      DEALLOCATE DB_CURSOR2
      SELECT C.Deger FROM #TBLF8941390E AS C WITH (NOLOCK) ORDER BY C.Id
      IF(ISNULL(OBJECT_ID('tempdb..#TBLF8941390E'),0)!=0) BEGIN DROP TABLE #TBLF8941390E END
  • Makale için teşekkür ederim.Kendi yaptığım yapıda transaction ve transactionscope kullanamıyordum.Sayesinizde uyarlayabildim.
  • Merhabalar Burak Bey,

    Bir türlü çözemediğim bir problemle karşı karşıyayım.
    Proje bir yerde hata alıyor. Aldığım hata Componentler ile alakalı "Views\Shared\Components\Header\Default.cshtml(691,58): error CS0103: T'' adı geçerli bağlamda yok" şeklindedir. Bu hatayı aldıktan sonra sadece profiler üzerinde görebildiğim

    "exec sp_executesql N'SET NOCOUNT ON;
    DELETE FROM [Users]
    WHERE [Id] = @p1;
    SELECT @@ROWCOUNT;

    ',N'@p1 int',@p1=1"

    ve
    "exec sp_executesql N'SET NOCOUNT ON;
    DELETE FROM [UserRoles]
    WHERE [Id] = @p0;
    SELECT @@ROWCOUNT;

    ',N'@p0 int',@p0=103"

    Execute oluşunu görüyorum. Projenin hiçbir yerinde bunu yapmasını sağlayacak bir yer yok. Bu nasıl olabilir?

    İyi çalışmalar.
  • elinize sağlık güzel bir yazı olmuş.
  • burak abi geçmişten günümüze ışık tutuyorsun
    eline sağlık teşekküler

Yorum ekle

Loading