Merhaba Arkadaşlar,
Veri merkezli uygulamalarda, katmanlar arasında veri alışverişi yarparken kullanıcı katmana veriler çoğu kez aracı tipler(DataTransferObject) vasıtasıyla taşınır. Özellikle veri katmanında orm teknolojilerinin kullanıldığı projelerde aracı servis katmanında, transfer objesi(dto) ve veritabanı objesi(entity) arasında kolonsal(properties) eşleştirmeyi tek tek yapmak yazılımcı için sıkıcı bir süreç. Konuyu koda dökerek somutlaştırılam:
// Entity { public int Id { get; set; } public string Name { get; set; } public string Surname { get; set; } public int Age { get; set; } public int Salary { get; set; } public bool IsActive { get; set; } } // Transfer Object internal class CustomerDto { public int Id { get; set; } public string Name { get; set; } public bool IsActive { get; set; } } internal class Program { private static void Main(string[] args) { // kaynak nesne, gerçek senaryolarda muhtemelen // sorgu ile veritabanı üzerinden elde edilir var customer = new Customer { Id = 1, Name = "aa", Surname = "bb", Age = 22, IsActive = true, Salary = 3000 }; // Entity üzerinden taşıyıcı nesne oluşturulur var customerDTO = new CustomerDto { //kolonsal olarak tek tek uye degiskenler atanır Id = customer.Id, Name = customer.Name, IsActive = customer.IsActive }; } }Görüldüğü üzere varlık(entity) tipinden taşıyıcı tipi elde etmek için üye değişken bazında tek tek atama yaptık. Eşleme(mapping) işlemini bizim için yapan AutoMapper adlı açık kaynak bir proje mevcut, nuget konsoluna "Install-Package automapper" komutunu girerek kütüphaneyi uygulamaya dahil edelim. Daha sonra aşağıdaki şekilde kullanıp sıkıcı eşleme işleminden kurtulalım ve de kodumuz daha yalın hale gelsin:
Görüldüğü üzere AutoMapper kütüphanesi 2 satır kodla bizim için eşleme işlemini halletti. Tabii bu işlemi yapmak için yansıma(reflection) kullanıdığı için peformans düşüşü söz konusu, özellikle işlem büyük koleksiyonlar üzerinden yapılıyorsa; bu senaryoya dair sentetik test sonuçları için güzel bir anlatım linkte mevcut: http://www.bayramucuncu.com/mapping-islemleri-ve-automapper-performans-testleri/
"Hazır kütüphanenin kodları açık bu işlemi nasıl yapıyor?" diye merak edip projenin kodlarını inceledim desem yalan olur :] Yerine kendimce "manuel" bir autoMapper yazdım:
Taaadaam! :] Görüldüğü üzere eşleme işlemi başarılı üstelik kullanım için AutoMapper'daki gibi "createMap" gibi fazladan bir hazırlık metodu çağrımında bulunmadık, yine map'leme metodu çağrımı daha sade oldu :] Şaka bir yana AutoMapper'ın createMap metodu farklı durumları(kaynak ve hedef ile eşlenmesi istenen üye değişkenlerinin isimlerinin farklı olması vs.) ele almak için kullanılır. Kullanım yanında performans da önemli bir kriter; hangi yöntemin daha performanslı çalıştığını söylemek yerine testi deneyerek görmeniz adına size bırakıyorum.
Umarım faydalı blog girdisi olmuştur, tarzsal kodlamalar :]
public class QMapper { public static object CloneClassicVersion(Customer source, Type targetType) { // ihtiyac duyulan tipe ait nesne runtime'da örneklenir var result = Activator.CreateInstance(targetType); // .net reflection api kullanılırak kaynak ve hedef tipin üye degiskenleri elde edilir var sourceProperties = source.GetType().GetProperties(); var targetProperties = targetType.GetProperties(); // hedef tipin uye degiskenleri uzerinden donguye girlir foreach (var targetProperty in targetProperties) { // linq kullanıp ikinci donguye girilmeyebilinirdi, okunabilirlik ve basitlik // adına böyle bıraktım, linq ifade: //var currentProperty = sourceProperties.First(a => a.Name == targetProperty.Name); foreach (var sourceProperty in sourceProperties) { // eslesen uye degiskenler saptanır, kaynaktan hedefe dogru deger atanır if (sourceProperty.Name == targetProperty.Name) { targetProperty.SetValue(result, sourceProperty.GetValue(source)); break; } } } return result; } public static TTarget CloneGenericVersion<TTarget>(object source) { var result = (TTarget)Activator.CreateInstance(typeof(TTarget)); var sourceProperties = source.GetType().GetProperties(); var targetProperties = typeof(TTarget).GetProperties(); foreach (var targetProperty in targetProperties) { foreach (var sourceProperty in sourceProperties) { if (sourceProperty.Name == targetProperty.Name) { targetProperty.SetValue(result, sourceProperty.GetValue(source)); break; } } } return result; } }Aynı örneği kendi yazdığımız mapper(QMapper) ile çalıştıralım:
Taaadaam! :] Görüldüğü üzere eşleme işlemi başarılı üstelik kullanım için AutoMapper'daki gibi "createMap" gibi fazladan bir hazırlık metodu çağrımında bulunmadık, yine map'leme metodu çağrımı daha sade oldu :] Şaka bir yana AutoMapper'ın createMap metodu farklı durumları(kaynak ve hedef ile eşlenmesi istenen üye değişkenlerinin isimlerinin farklı olması vs.) ele almak için kullanılır. Kullanım yanında performans da önemli bir kriter; hangi yöntemin daha performanslı çalıştığını söylemek yerine testi deneyerek görmeniz adına size bırakıyorum.
Umarım faydalı blog girdisi olmuştur, tarzsal kodlamalar :]
Hiç yorum yok:
Yorum Gönder