Asp.NET Core — Dapper Kullanımı

Engincan Veske
SDTR
Published in
6 min readMay 14, 2021
Dapper

Herkese merhaba,

Bu yazımda Micro-ORM aracı olarak Dapper kullanarak basit bir Todo uygulamasını nasıl geliştirebileceğimizden bahsedeceğim. İlk olarak Dapper’ın ne olduğundan ve özelliklerinden bahsederek işi koyulalım.

Dapper Nedir? Özellikleri Nelerdir?

Hızın önemli olduğu yerlerde genellikle ORM araçları tercih edilmez. Yavaştırlar. Bu gibi durumlara Micro-ORM’ler tercih edilebilir. Micro kelimesinden de anlaşılabileceği gibi bu tarz araçlar EF gibi devasa ORM araçlarının sağladığı bütün özellikleri sağlamak yerine tek bir özelliği yerine getirirler (Object mapping).

  • Performans testlerine göre en hızlı Micro-ORM / ORM araçlarından biridir. Bu sebeple King of Micro ORM olarak da adlandırılır.
  • Lightweight’tir. Tek bir .dll olarak uygulamaya eklenir.
Dapper.dll
  • Stack Exchange şirketi tarafından geliştirilmiştir (Stackoverflow).
  • EF Core’da olduğu gibi kolay sorgu (query) yazma imkanı sağlar.
  • Code First gibi bir migration yaklaşımı sunmaz daha ziyade hali hazırda varolan veritabanı tabloları üzerinden işlemler geliştirilmesine izin verir.
  • Uygulama içinde Raw SQL sorguları ile sorgulama yapılabileceği gibi tanımlanmış olan “Stored Procedure”’ler çağırılarakta ilgili veritabanı işlemleri yerine getirilebilir.

DapperTodoDemo Uygulamasına Başlayalım

Uygulamanın kaynak koduna buradan ulaşabilirsiniz.

DapperTodoDemo Uygulaması

DapperTodoDemo uygulamasını tamamladığımızda yukarıdaki görsele benzer bir sayfa elde etmiş olacağız. Öyleyse uygulamamıza başlayalım.

İlk olarak Todo uygulamamız için “DapperTodoDemo” adında bir veritabanı ve bu veritabanın içinde de “TodoItems” isimli bir tablo oluşturalım. (Ben veritabanı olarak MSSQL kullanıyorum. Siz istediğiniz bir veritabanı ile yola devam edebilirsiniz.)

DapperTodoDemo Veritabanı

“TodoItems” isimli tablomuzu da aşağıdaki görselde olduğu gibi tanımlayabiliriz.

TodoItems Tablosu

Veritabanını oluşturduktan sonra artık uygulamamıza başlayabiliriz. Uygulamamızda Domain, Application, Infrastructure ve Web olmak üzere 4 katmanlı bir yapı oluşturacağız. Infrastructure katmanında uygulamamızın Dapper ile alakalı entegrasyonunu sağlayacağız.

DapperTodoDemo Solution Yapısı

İlk olarak “DapperTodoDemo” adında boş bir solution oluşturalım. Ve ilgili katmanları tanımlayalım.

Domain Katmanı

Oluşturmuş olduğumuz Solution’a “DapperTodoDemo.Domain” adında bir class-library tanımlayalım. Burada, “TodoItems” isimli veritabanındaki tablomuza karşılık gelecek olan entity’i tanımlayacağız.

TodoItemadında bir sınıf ve TodoStatusadında bir enum oluşturalım.

TodoItem.cs
TodoStatus.cs

Burada oluşturmuş olduğumuz “TodoItem” sınıfı veritabanındaki dbo.TodoItems tablosuna karşılık gelen bir entity görevi görmekte. Oluşturmuş olduğumuz bu sınıf sayesinde veritabanına yapmış olduğumuz sorgular sonucunda dönen değerleri deserialize ederek ilgili sınıf üzerinden işlemlerimize devam edebilmekteyiz.

Daha sonra ise “Repository” adında bir klasör oluşturalım ve bu klasör içine “ITodoItemRepository” adında bir interface tanımlayarak ilgili CRUD işlemlerini belirleyelim.

ITodoItemRepository.cs

Bu oluşturmuş olduğumuz interface’i, 4 temel CRUD işlemini tanımladığımız ve Infrastructure katmanında implemente edeceğimiz methodları belirttiğimiz yer olarak düşünebilirsiniz. (Uygulamanın basit bir yapıda kalması ve amacından sapmaması için burada bir Generic Repository tanımlamak istemedim. https://github.com/ericdc1/Dapper.SimpleCRUD eğer Generic Repository kullanmak isterseniz bu repo üzerinden uygulayabilirsiniz.)

Domain katmanında ilgili sınıfları tanımladıktan sonra, oluşturmuş olduğumuz Repository interface’ini implemente etmek için Infrastructure katmanını oluşturalım.

Infrastructure Katmanı

Solution’a “DapperTodoDemo.Infrastructure” adında yeni bir class-library ekleyelim. Ardından projemize Dapper paketini nuget aracılığı ile kuralım. CLI üzerinden ilgili paketi yüklemek istersek,

dotnet add package Dapper --version 2.0.90

komutunu kullanabiliriz. Dapper paketini kurduktan sonra artık Domain katmanında tanımlamış olduğumuz ITodoItemRepository interface’ini implemente etmeye başlayabiliriz. Bunun için TodoItemRepository isminde bir sınıf oluşturalım ve ilgili sınıfı aşağıdaki kod parçacığı ile dolduralım.

TodoItemRepository.cs

İlgili sınıfı inceleyecek olursak, ilk olarak veritabanı ile bağlantıyı sağlamak için SqlConnection adındaki sınıfı oluşturarak bu sınıfa connection-string’i parametre olarak geçiyoruz. Bu işlemler sonucunda ilgili SqlConnection sınıfının yardımcı methodları olan QueryAsync<>, QueryFirstAsync<> ve ExecuteAsync gibi methodlarla ilgili Raw Sql sorgusunu yazarak veritabanından dönen değerleri Domain katmanında tanımlamış olduğumuz “TodoItem” isimli sınıf ile map’lemiş (Dapper gerçek anlamda burada işe dahil olmuş oluyor) oluyoruz . (Burada ilgili yardımcı methodların senkron hallerinin de olduğunu belirtmek isterim.)

Burada kullanmış olduğumuz yardımcı methodlar dışında birçok yardımcı methodun daha olduğunu belirtmek isterim. Örneğin, “BeginTransaction” methodu ile transaction başlatılabilir veya “QuerySingleAsync” ile birlikte ilgili nesne tek dönmez ise veya bulunamazsa Exception fırlatması sağlanabilir.

Not: Buradan sonraki bölüm Dapper ile yakından alakalı değildir. Daha ziyade ilgili uygulamanın tamamlanması için gereken son adımları göstermektedir.

Application Katmanı

Application katmanı, kullanıcının uygulamamızda gerçekleştirdiği işlemlere karşılık gelen use-case’lerin tanımlandığı bir katmandır ve uygulamamızın Business Logic’i burada tanımlanır.

Solution’a “DapperTodoDemo.Application” adında yeni bir class-library ekleyelim ve ilgili use-case’lere karşılık gelen methodları ve DTO’ları (Data Transfer Object) tanımlayalım.

TodoItemDto.cs
CreateUpdateTodoItemDto.cs

Şimdi de ilgili use-case seneryolarımızı implemente eden TodoItemAppService sınıfını oluşturalım ve aşağıdaki gibi dolduralım.

TodoItemAppService.cs

Ben uygulamada ObjectMapper paketini kullanarak ilgili TodoItem entity’sini TodoItemDto (output DTO) olarak map’leyerek ilgili sonucu geri döndürüyorum. (DTO ve ObjectMapper kavramları makalenin konusu dışında olduğu için bu kısımları geçiyorum. Oluşturmuş olduğum repository üzerinden ilgili mapping yapılandırmasını inceleyebilirsiniz.)

Uygulamamızdaki gerçekleştirilecek işlemleri (Todo ekleme, silme, güncelleme, listeleme) de tanımladığımıza göre sıra Web katmanını (UI) oluşturmaya geldi.

Web Katmanı (Presentation Layer)

Solution’a “DapperTodoDemo.Web” adında bir razor web application oluşturarak uygulamamızın UI’ını tasarlamaya başlayalım. Uygulamamızda gerçekleştirecek olduğumuz ekleme, silme, güncelleme ve listeleme işlemleri için bir nevi SPA uygulaması geliştiriyormuş havası vermek için PartialView oluşturalım ve ilgili işlemler gerçekleştikten sonra ilgili sayfayı ajax çağrısı ile birlikte render edelim (oluşturmuş olduğumuz PartialView’u her işlem sonucunda yapmış olduğumuz veritabanı sorgusundan dönen değere göre güncelleyelim). Bunun için ilk olarak _Todo.cshtml adında bir dosya oluşturalım. (Pages klasörü altında)

_Todo.cshtml

İlgili PartialView’u incelersek en üst satırlarda model TodoViewModel isminde bir sınıfın tanımlanmış olduğunu görüyoruz. Bu ilgili model sınıfı sayesinde use-case’ler gerçekleştikten sonra ilgili verileri güncelleyerek PartialView’ı yeniden render edeceğiz. Öyleyse TodoViewModel sınıfını tanımlayalım. (Models klasörü oluşturalım ve bu klasör içinde bu sınıfı tanımlayalım)

TodoViewModel.cs

Geri dönüp, _Todo PartialView’una bakacak olursak bu sınıfta tanımlanmış olan TodoItem’ları listelediğimizi daha net bir şekilde görebiliriz. (İlgili partial-view’u çağırken bu sınıfı ve ilgili property’sini de tanımlayarak çağırmamız gerektiğini hatırlatmak isterim.)

İlgili PartialView’u ve modelini tanımladıktan sonra bu PartialView’da gerçekleşen kullanıcı işlemleri sonucunda tetiklenecek olan event’leri tanımlamak için Todo.js isminde bir dosya oluşturalım. (Ben bu dosyayı /wwwroot/js altında oluşturdum)

Todo.js

Burada kodları incelersek kullanıcın uygulamadaki formları (ekleme ve güncelleme işlemleri için) doldurup submit etmesi durumunda bir ajax isteyi yapılmakta ve dönen sonuç _Todo PartialView’umuzdaki ilgili container’ı güncelleyerek render etmekte. Son olarak burada yapılan ajax isteklerinin endpointlerini tanımlayalım. Bunun için controller tanımlamamız gerekiyor. (TodoItemController.cs)

Oluşturmuş olduğumuz TodoItemControllersınıfını aşağıdaki kod parçacığı ile dolduralım.

TodoItemController.cs

Burada dikkat edecek olursak, bütün methodlarda geri dönüş değeri olarak PartialViewResult dönmekteyiz. Bu sayede bu methodlara gelen her istek sonucunda bize bir HTML çıktısı üretilecek (yeni veriler ile (todoItems)) ve ilgili container ile birlikte bu çıktıyı değiştirerek verileri güncel bir şekilde ekranda görüntüleyebileceğiz. İlgili controller’ı da tanımladıktan sonra artık tek yapmamız gereken şey ilgili PartialView’u ana-sayfamızda göstermek. Bunun için /Pages/Index.cshtml.cs dosyasını açalım ve aşağıdaki gibi güncelleyelim.

Burada basit bir şekilde ITodoAppService’i injecte ederek bütün Todo’ları listelemekteyiz. Daha sonra ise bu Todo’ları oluşturmuş olduğumuz TodoItems değişkene atayarak PartialView’umuza geçeceğiz. Bu sayede ilgili PartialView bu verileri kullanarak ekranda gösterme işlemini gerçekleştirecek. Son olarak ilgili component’i ana-sayfamızda göstermek için cshtml dosyasını düzenleyelim.

Index.cshtml

Artık uygulamamızı çalıştırarak son çıktıyı görebiliriz. (Herhangi bir hata ile karşılaşırsanız ilgili Github reposuna bakabilirsiniz.)

Okuduğunuz için teşekkürler. Umarım faydalı olmuştur.

--

--