511
0

איך לעבוד עם AutoMapper ב#C

511
זמן קריאה: 3 דקות

מה זה AutoMapper?

AutoMapper מוכרת היטב בקרב קהילת מפתחי NET.,
מדובר בספרייה קטנה ופשוטה (Nuget) שנוצרה כדי לפתור בעיה נפוצה – מיפוי אובייקטים ותעזור לכם להיפטר מקוד שממפה אובייקט אחד למשנהו.

תוכן עניינים

הבעיה

דוגמא אחת לבעיה נפוצה היא להביא אובייקט מטבלה ואז להעביר את כולו / חלקו לאובייקט View Model.

				
					UserEntity user = GetUserFromDB();

var userDTO = new UserDTO()
{
    Id = user.Id,
    FirstName = user.FirstName,
    LastName = user.LastName,
    Email = user.Email,
    BirthYear = user.BirthDate.Year
};
				
			

בדוגמא שהבאתי זה לקח 7 שורות קוד, עכשיו תנסו לדמיין מה קורה שיש 30 משתנים באובייקט.

ביננו? מדובר בקטעי קוד מיותרים ואפילו קצת משעממים לכתיבה, חוזרים על עצמם בטירוף במיוחד בפרוייקטים שמתקשרים עם Database וצד לקוח.
אז למה שלא נתייעל ע”י כלי שיעשה זאת בשבילנו?

מתחילים

תחילה יש להתקין את הספריה AutoMapper כפי שמתקינים כל ספריית Nuget

כדי להמחיש איך הספריה עובדת יצרתי 2 מחלקות שיש בינהן קשר ונרצה למפות אותם בקוד שלנו

				
					public class UserEntity
    {
        public Guid Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Email { get; set; }
        public string Password { get; set; }
        public DateTime BirthDate { get; set; }
    }
				
			
				
					public class UserDTO
    {
        public Guid Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Email { get; set; }
        public int BirthYear { get; set; }    
}
				
			

מיפוי ברירת מחדל

ללא הגדרת תצורה ספציפית, AutoMapper יתאים בין משתנים בהתבסס על שמם.
כברירת מחדל, הוא יתעלם מפניה לNull Exception בעת מיפוי סוגי המקור והיעד.
נעשה זאת כך:

				
					var user = new UserEntity()
{
    Id = Guid.NewGuid(),
    FirstName = "Amir",
    LastName = "Shtaiman",
    Email = "admin@codetime.co.il",
    Password = "12345678",
    BirthDate = new DateTime(1988, 06, 03)
};
            
var config = new MapperConfiguration(cfg => cfg.CreateMap<UserEntity, UserDTO>());
var mapper = config.CreateMapper();
UserDTO userDTO = mapper.Map<UserDTO>(user);
				
			

הקוד שמעל הטקסט ייצור אובייקט יעד UserDTO עם Id ומאפיינים (שם, משפחה, אימייל) התואמים לאובייקט המשתמש המקורי, אך לא תיזרק שגיאה כתוצאה מכך שאין את המאפיינים Password, BirthDate באובייקט UserDTO.
כמו כן, המאפיין BirthYear של UserDTO יהיה אפס מכיוון שאין משתנה כזה באובייקט המקור.

מיפוי מותאם אישית

לא תמיד ברירת המחדל תפתור לנו את מה שרצינו בקלות, למשל בדוגמא שנתתי BirthDate לא הפך לBirthYear.
קטע הקוד הבא ידגים כיצד אנו יכולים למפות את המשתנה BirthDate של האובייקט UserEntity למשתנה BirthYear מסוג UserDTO.

				
					var config = new MapperConfiguration(cfg => cfg.CreateMap<UserEntity, UserDTO>()
                        .ForMember(dest => dest.BirthYear, 
                            opt => opt.MapFrom(src => src.BirthDate.Year)));
                   

var mapper = config.CreateMapper();
UserDTO userDTO = mapper.Map<UserDTO>(user);
				
			

אובייקט היעד userDTO שהתקבל יהיה דומה לדוגמא הראשונה שלנו, אך הפעם המשתנה BirthYear לא יהיה 0 אלא יכיל את השנה מהמשתנה BirthDate.

פרופילים

דרך טובה ונקייה לארגן את תצורות המיפוי שלנו היא באמצעות פרופילים. ניצור מחלקות שירשו ממחלקת פרופיל (מחלקה קיימת בספריה של AutoMapper) ונכניס את התצורה לבנאי:

				
					public class UserManagementProfile : Profile
{
    public UserManagementProfile()
    {
        CreateMap<UserEntity, UserDTO>()
            .ForMember(dest => dest.BirthYear, 
            opt => opt.MapFrom(src => src.BirthDate.Year));
    }
}
				
			

עכשיו הלוגיקה נמצאת במחלקה אחרת (ניתן גם לקבוע שם לוגיקות מרובות ולא רק אחת)
וכך זה נראה אחרי שימוש בפרופילים (יכולנו להוסיף יותר מפרופיל אחד במקרה הצורך):

				
					
            var user = new UserEntity()
            {
                Id = Guid.NewGuid(),
                FirstName = "Amir",
                LastName = "Shtaiman",
                Email = "admin@codetime.co.il",
                Password = "12345678",
                BirthDate = new DateTime(1988, 06, 03)
            };

            var mapper = new MapperConfiguration(cfg => cfg.AddProfile<UserManagementProfile>())
                .CreateMapper();
            UserDTO userDTO = mapper.Map<UserDTO>(user);
				
			

Dependency Injection

הזרקת תלות זה חלק אינטגרלי ב ASP.NET Core, אך במקרה הזה כדי להשתמש בו ב- AutoMapper נצטרך תצורה נוספת וחבילת Nuget נוספת –
AutoMapper.Extensions.Microsoft.DependencyInjection

לאחר שהתקנו את הnuget המדובר נקבל את היכולת להוסיף את AutoMapper בתור service (בקובץ Startup.cs)

				
					Install-Package AutoMapper.Extensions.Microsoft.DependencyInjection

				
			
				
					public void ConfigureServices(IServiceCollection services)
{
    Mapper.Initialize(cfg => cfg.AddProfile<MappingProfile>());

    services.AddAutoMapper(typeof(Startup));
    services.AddControllersWithViews();
}
				
			
אמיר שטיימן
WRITEN BY

אמיר שטיימן

Backend Engineer @Cynet
ביום יום מפתח Backend בסביבת SaaS, מיקרו סרביסים בשילוב של מערכות מבוזרות. בזמני הפנוי - לומד ומשתדרג בעולם התוכנה, אוהד מכבי חיפה, פלייסטיישן ובירה עם חברים :)
Linkedin | Twitter

כתיבת תגובה

האימייל לא יוצג באתר. שדות החובה מסומנים *