استفاده از AutoMapper در MVC

شنبه 15 آذر 1393

در این مقاله سعی داریم تا مفهوم جدیدی تحت عنوان AutoMapper را در MVC به شما معرفی کنیم.AutoMapper زمانی استفاده می شود که بخواهیم پیچیدگی بایند کردن مدل و ارتباط با entity ها را کاهش دهیم.

استفاده از  AutoMapper  در MVC

زمانی که ما برای یک محیط واقعی کد می زنیم، کارهای بسیاری میکنیم تا کدمان قابل فهم تر باشد و bug  های موجود در آن را بهتر بتوان شناسایی و رفع کرد.عمدتا روی این امر تمرکز میکنیم که کد مان قابلیت استفاده مجدد را داشته باشد و تا جای ممکن سعی میکنیم تا هر کدی را که می توانیم تا جای ممکن در متدهای متداول و مورد استفاده خود بگذاریم تا با این کار، هم در زمان برنامه نویس صرفه جویی شود و هم هزینه های پشتیبانی کاهش یابد.

در این مقاله سعی داریم تا مفهوم جدیدی تحت عنوان AutoMapper  را در  MVC  به شما معرفی کنیم.AutoMapper

   زمانی استفاده می شود که بخواهیم پیچیدگی  بایند کردن مدل و ارتباط با entity  ها را کاهش دهیم.

مشکل واقعی:
ما معمولا ارتباط زیادی با  entity  های database  مان و بایند کردن مدلمان با آنها داریم.چیزی که در نهایت ما با آن سرکار داریم چنین چیزی است:

 

    public UserDto GetUserById(string id)  
    {  
          var userDto = new UserDto();  
      
          using(var context = new EntityDBContext())  
          {  
      
                var user = context.Users.Where(ID => ID.user_id == id).FirstOrDefault();  
                if (user != null)  
                {  
                      userDto.UserId = user.user_id;  
                      userDto.Name = user.user_name;  
                      userDto.Address = user.user_address;  
                      userDto.PhoneNo = user.user_phoneNo;  
                      userDto.City = user.user_city;  
                }  
          }  
      
          return userDto;  
    }  


در اینجا میبینیم که پنج property  در هر کلاس داریم. و کاری که باید انجام دهیم این است که محتوای db  را  به مدل خود بایند کنیم و سپس آن را به View  پاس دهیم، در این مرحله این کار خیلی ساده به نظر می رسد.
مشکل اصلی وقتی به وجود می آید که ما 25-30 فیلد در رکورد داشته باشیم و بخواهیم این بایند کردن کد را برای همه آن ها در پروژه تکرار کنیم. Copy  ، Paste  حتی وقتی فقط 5  property  داریم.خیلی سخت و رنج آور است.
پیچیدگی بیشتر وقتی به وجود می آید که برای هر  View  یک ViewModel  جداگانه داشته باشیم.در این صورت کار شما دوچندان می شود،اول باید مدل خود را بایند کنید و سپس باید دوباره آن را به viewmodel  بایند کنید.
برای گذر از این وضعیت خسته کننده  AutoMapper  ایجاد شد.


درباره  AutoMapper
AutoMapper  یک کتابخانه open source   است که توسط  GitHub  ایجاد شده است.CodePlex  درمورد AutoMapper  این طور میگوید: "AutoMapper  یک object-object mapper  است.  Object-object mapping  اینطور کار میکند که object  ورودی از یک Type  را به  object  خروجی  از type  دیگری تبدیل می کند.چیزی که  AutoMapper  را جذاب میکند این است که  AutoMapper  قواعدی را فراهم کرده است تا بفهمیم چگونه  type A   را بهtype B   ، Map  کنیم.تا زمانیکه type B ، از قواعد  AutoMapper  پیروی میکند،تقریبا هیچ پیکربندی برای map  کردن دو type  نیاز نیست."

می توانید از این لینک AutoMapper را بگیرید و sample  ها و document  ها را در آن  ببینید.
 

استفاده از  AutoMapper
حالا خواهیم دید که AutoMapper  چگونه مشکل ما را حل خواهد کرد.AutoMapper  متد CreateMap<T1,T2>  را ایجاد میکند که این متد Mapping  بین دو کلاس را انجام میدهد.بنابراین، این کد میتواند با کد زیر جایگزین شود:

    public UserDto GetUserById(string id)  
    {  
          var userDto = new UserDto();  
      
          using(var context = new EntityDBContext())  
          {  
      
                var user = context.Users.Where(ID => ID.user_id == id).FirstOrDefault();  
                Mapper.CreateMap<User,UserDto >();  
                userDto = Mapper.Map<User,UserDto >(user);  
          }  
      
          return userDto;  
    }  


User  یک type از کلاس DBContext  است و UserDTO ، کلاس DTO  ماست که map  میشود.
در آخر برای map  کردن تمام داده ها به متد Map<T1,T2>  از کلاس  AutoMapper  احتیاج داریم.بنابر این کد نهایی به صورت زیر است:


    using(var context = new EntityDBContext())  
    {  
      
          var users = (from users in context.Users select users).ToList()  
          Mapper.CreateMap<User,UserDto >();  
          foreach(var user in users)  
          {  
                userDto = Mapper.Map<User,UserDto >(user);  
                userDtosList.Add(userDto);  
        }  
      
    }  


بنابر این با این کار از روش خسته کننده ی قبلی نجات پیدا میکنیم.عملگر  CRUD  ما ساده و سازماندهی شده است.فقط کافی است که کلاس ها را map  کنید و سپس عمل post  را انجام دهید. برای بدست آوردن تمام جزئیات ، فقط نیاز داریم تا به کد قبلی یک تغییر بدهیم و آن هم این است که شئ  UserDto  را به لیست  UserDTos  اضافه کنیم.

Mapper.AssertConfigurationIsValid();

همچنین میتوانیم به جای Map  از DynamicMap  استفاده کنیم.

نکاتی که باید به یاد داشته باشید:
برای اینکه عمل mapping  انجام شود باید نام هر دو کلاس یکسان باشد.همچنین، data type  ها باید با هم  match  باشند. این به این معناست که اگر  type A  یک property  دارد که از نوع  long  است،بنابراین type B  هم باید  property  ای داشته باشد که از نوع  long  است.در غیر این صورت Automapper  کار نمیکند.برای اینکه بفهمیم mapping  ما کار میکند یا  نه ، به صورت زیر عمل میکنیم:
Mapper.AssertConfigurationIsValid();

اگر کلاس های Dto  و  DBContext   ، collection  هایی را به عنوان  property  داشته باشند ، ما ابتدا باید آن کالکشن ها را  map  کنیم و سپس میتوانیم parent  هارا  map  کنیم.بنابراین دو روش برای ایجاد map  خواهیم داشت. بهتر است از آن در متد  Initialize()  استفاده کنیم.مانند زیر:


    Mapper.Initialize(cfg =>  
    {  
          cfg.CreateMap<User, UserDto>();  
          cfg.CreateMap<Recipts, ReciptsDto>();  
      
    });  


متد ForMember()
متد مهم و پرکاربرد دیگری که AutoMapper  برای ما فراهم کرده است ، متد ForMember()  است.تصور کنید که کلاس dbContext ما ، دو  property   با نام های  FirstName  و LastName  دارد، درحالیکه مدل یا viewmodel  ما property  ای با عنوان  FullName  را دارد .در این حالت نیازی نداریم که دو property  جدید به مدل یا viewmodel  مان اضافه کنیم.میتوانیم از متد ForMember()  برای mapping  استفاده کنیم.


Mapper.CreateMap<User,UserDto>().ForMember(user => user.Fullname,
map => map.MapFrom(p => p.FirstName + " " + p.LastName));


متد Ignore()
این متد زمانی کاربرد دارد که ما property  اضافه ای در شئ  مقصدمان داریم.این سناریو در ViewModel و هنگامی مورد استفاده قرار میگیرد که property  اضافه ای داشته باشیم.بنابر این میتوانیم از کد زیر استفاده کنیم:
Mapper.CreateMap<User,UserDto >()
.ForMember(dt=>dt.SessionId,options=>options.Ignore())
.ForMember(dt=>dt.PROGRAM_NAME,options=>options.Ignore());


نتیجه:
با استفاده از  AutoMapper  زندگی راحت تر می شود. پیشنهاد میکنیم که برنامه نویسان اگر شرکت به آنها اجازه می دهد از این روش استفاده کنند.
میتوانید به این لینک مراجعه کنید و document ها و sample  های مربوطه را مشاهده کنید.
 

صبا ذاکر

نویسنده 18 مقاله در برنامه نویسان

کاربرانی که از نویسنده این مقاله تشکر کرده اند

در صورتی که در رابطه با این مقاله سوالی دارید، در تاپیک های انجمن مطرح کنید