MVC AutoMapper ve DTO kavramı
Bu yazıda uygulamalarımızda DTO ( Data Transfer Object ) kavramını AutoMapper ile nasıl kolay ve anlaşılır hale getiriyoruz bunu inceleyeceğiz. Özellikle EntityFramework kullanılan web uygulamlarında model kavramını iyi işlemek gerekir. Öyle ki standart bir MVC web uygulaması oluşturduğumuzda Models klasörü otomatik oluşur. Bunun anlamı şudur , ‘View’ları besleyeceğiniz sınıfları bu klasör altında toplayın’.
O halde view ile controller arasında veri alışverişini View model ile sağlıyoruz ve bu modeller aynı zamanda bize insert update işlemler içinde data sağlıyor. Fakat View modellerimizi direk olarak EntityFramework ile konuşturamayız. Çünkü EntityFramework Database objelerini oluştururken her bir tabloyu bir class kolonları da birer property olarak yorumlar ve tüm tabloları objelere dönüştürür (Class). Bu sınıfların genel adı Data Model olur. EntityFramework CRUD işlemleri için kendi oluşturduğu Data Model’leri kullanır..
Burada kısa bir es verelim, Data model – View ‘da kullanılabilir mı ? diye düşündüyseniz cevap evet.. Teknik olarak kullanılabilir. Fakat doğru olmaz. Çünkü tablodaki bütün alanları view’da göstermek istemeyebiliriz. Ayrıca sadece Business için kullanmak istediğimiz değişkenlerimiz de olabilir. Bu tür ihtiyaçlarımızı Data Model üzerinden sağlayamayız. Diğer bir bakış açısında ise , katmanlı mimari yaklaşımında database işlemlerinin yapıldığı ayrı bir Library oluşturulur ve WebUI katmanının (view – controller) Data katmanından haberi olmaz. Bu tür yapılarda WebUI ile Data katmanı arasında iletişimi sağlayan Business katmanı oluşturulur ve tüm iletişim bu katman üzerinden yürütülür.
Şimdi konumuza geri dönelim ve biraz AutoMapper konuşalım.
Veritabanı uygulamalarında , verinin işlenmesinde 2 farklı ihtiyaçla karşılaşırız. Bunlar verinin CRUD işlemlerine ve kullanıcı arayüzüne aktarılmasıdır. Yukarıda anlattığımız gibi bir yapıda gelen veriyi arayüze aktarmamız için View model’e çevirmemiz gerekir, aynı şekilde arayüzden gelen bir veriyi database’e aktarmamız için view model’i data model’e çevirmemiz gerekir. Yani kodlarımızda aşağıdaki gibi gereksiz bir kod bloğu oluşur.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
List<MyViewModel> model = (..data..).Select(p => new MyViewModel { Id = p.Id, Name = p.Name, SurName = p.SurName .. .. .. }); |
Aynı şekilde herhangi bir CRUD işleminde ise bu çevirir tam tersi yapılır. Bu durum 3-5 alan için çok problem olmaz fakat değişken/kolon sayısı arttıkça çok can sıkıcı bir hal almaya başlar.
Şimdi kodlara geçmeden önce AutoMapper implementasyonunda nasıl bir yol izleyeceğimden bahsedeyim.
Öncelikle Mapper ayarlarımızı yapacağımız bir wrapper sınıf oluşturacağız.
Wrapper sınıfının amacı Mapper çevirilerini tanımlamak olacak. Ayrıca bu dönüşümlerde ignore edilecek alanları da belirteceğiz.
Hemen ardından uygulama ayağa kalktığında Global.asax içersinde uygulamamıza bizim mapper sınıfımızın olduğunu belirteceğiz. Ardından bir Extension sınıfı ile (Extension ile ilgili bilgiyi bu makalemizde bulabilrisiniz) Data Model ve View Model çevirilerimizi ekleyeceğiz.
MapWrapper.cs
Customer modeli için Data model – View model ve ViewModel – Data Model çevirisi eklendi. View Model – Data Model çevirisinde CustomerType alanını dikkate alınmayacağı (ignore) belirtildi.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
public class MapWrapper { public static void Run() { SetMappings(); } private static void SetMappings() { var config = new MapperConfigurationExpression(); config.CreateMap<Customer, CustomerModel>(); config.CreateMap<CustomerModel, Customer>() .ForMember(f => f.CustomerType, opt => opt.Ignore()); } } |
Global.Asax Application_Start’a eklediğimiz kod ile uygulamamız ile Mapper arasındaki ilişki kuruldu.
1 2 3 4 5 6 7 8 |
protected void Application_Start() { MapWrapper.Run(); } |
MapExtension.cs
Aşağıdaki Extension sınıfı ile CRUD işlemleri için ToEntity , UserInterface işlemlerimiz için ToModel adında iki metot ekledik. this anahtarı ile referans olduğu objeye bu metodu eklemiş olduk.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
public static class MapExtensions { public static CustomerModel ToModel(this Customer entity) { return Mapper.Map<Customer, CustomerModel>(entity); } public static Customer ToEntity(this CustomerModel model) { return Mapper.Map<CustomerModel, Customer>(model); } } |
Şimdi kod içerisinde bu çevirileri yapalım.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
public CustomerModel GetCustomer(int id) { //Customer customerData = // dbden gelen veri return customerData.ToModel(); } public void SaveCustomer(CustomerModel model) { var entity = model.ToEntity(); } |
Umarım faydalı bir yazı olmuştur.