انجام عملیات CRUD با استفاده از AutoMapper در MVC

جمعه 24 اردیبهشت 1395

در این مقاله با استفاده از AutoMapper و تکنولوژی MVC ، در چند مرحله ساده عملیات CRUD را پیاده سازی می کنیم. همچنین مفاهیم مربوط به AutoMapper و کاربرد های آن را بیان می کنیم.

انجام عملیات CRUD با استفاده از AutoMapper در MVC

مقدمه

وقتی با realtime programming (برنامه نویسی برای سیستم های بلادرنگ) سر و کار داریم ، با چالش های زیادی مواجه می شویم. این مقاله یک مفهوم جدید به نام Auto Mapper را در MVC معرفی می کند که به وسیله آن می توانیم بر چالش های بزرگی که برای ارتباط با Data Entity و bind  کردن داده ها به model  مواجه هستیم ، غلبه کنیم.

چالش های موجود

برخی اوقات هنگام مواجه شدن با Entity های بلادرنگ (real time) و متصل کردن آن ها به model هایمان ، به حالت زیر می رسیم :

var dbContext = new MyDBDataContext();
var userDetails = dbContext.Users.FirstOrDefault(userId => userId.UserId == id);
var user = new LearningMVC.Models.User();
    if (userDetails != null)
    {
        user.UserId = userDetails.UserId;
        user.FirstName = userDetails.FirstName;
        user.LastName = userDetails.LastName;
        user.Address = userDetails.Address;
        user.PhoneNo = userDetails.PhoneNo;
        user.EMail = userDetails.EMail;
        user.Company = userDetails.Company;
        user.Designation = userDetails.Designation;
    }
return View(user);

درک مفهوم کدی که در بالا نوشته شده است، چندان سخت نیست. در کد بالا ، یک نمونه از MyDBDataContext به وسیله ی LinqTOSql Context class ساخته شده است (using "var dbContext = new MyDBDataContext();")  سپس جزئیات اطلاعات کاربر از یک جدول خاص گرفته می شوند و در متغیر userDetails ذخیره می شوند. ما یک مدل از پیش ساخته شده به نام "User" داریم ("LearningMVC.Models.User()") ، که دارای Property های مشابه با Users class هایی است که از پایگاه داده تولید شده اند. حالا ما Property  های نمونه ای که از model ساختیم را با Property  های نمونه ای که از User class (از پایگاه داده) ساختیم ، مقداردهی می کنیم ، به این روشی که گفتیم می توانیم view  ها را در MVC  پر کنیم .

در اینجا می بینیم که 8 خصوصیت (Property) مشابه داریم که هر کدام در کلاس جداگانه ای قرار دارند، یکی از آن ها در Model قرار دارد و یکی دیگر در Users class قرار دارد. و کاری که ما می خواهیم انجام بدهیم این است که می خواهیم این property  ها را یکی یکی به model  وصل کنیم و سپس model  را به View  متصل کنیم. حالا می خواهیم بببینیم مشکل این روش کجاست ؟ اگر ما 100 ستون از اطلاعات داشته باشیم که از پایگاه داده گرفته شوند و همچنین مدل ما هم همین تعداد از property  ها را داشته باشد، و بخواهیم کد را 7-6 بار در زمان های متفاوت و به طریق مختلف تکرار کنیم ، آیا ما همچنان از این سیاست استفاده خواهیم کرد؟ سیاستی که هر بار هر کدام از Property ها را از پایگاه داده بگیریم و به model  وصل کنیم! باور کنید اگر بخواهیم به این روش ، این برنامه را بنویسیم ، زمان طولانی ای را از ما خواهد گرفت .

برای غلبه بر چنین مشکلاتی ، AutoMapper به بازار آمد. این روش ، به کار و تلاش کمتری نیاز دارد و همچنین زمان اجرا را تا حد زیادی کاهش می دهد.

Auto Mapper

AutoMapper یک تکنولوژی است که به صورت open source  در GitHub نیز ارائه شده است.

همانطور که در صفحه ی AutoMapper CodePlex web page نیز گفته شده است ، AutoMapper یک  object-object mapper است . (شی را به شی می نگارد.) Object-object mapping به این روش کار می کند که یک شی ورودی با یک نوع خاصی را می گیرد و در خروجی یک شی با نوع دیگری را تحویل می دهد. (شی ورودی را به یک شی دیگر تبدیل می کند و به عنوان خروجی تحویل می دهد) . نکته ای که AutoMapper  را برای ما جالب می کند این است که AutoMapper می تواند با استفاده از یک سری قوانین و قواعد مفید و جالب، حتی در یک کد کثیف و طولانی ، یک روش mapping  بهینه و خوب به ما بدهد. تا زمانی که نوع B  از قوانین AutoMapper  (که در زمان ساخت ارتباط، ایجاد شده اند)   پیروی کند، هیچ گونه پیکر بندی ای برای map  کردن دو نوع داده A  و B نیاز نیست.بنابراین ، AutoMapper راه حل مناسبی برای حل مشکلات mapping  ما محسوب می شود.

نصب AutoMapper

ابتدا باید NuGet Package Manager را بر روی Visual Studio IDE نصب کنید. پس از انجام این کار، مسیر زیر را طی کنید:

"Tools" -> "Library Packet Manager" -> "Packet manager Console"

سپس در پنجره ای که در انتهای صفحه باز می شود ، عبارت زیر را تایپ کنید :

PM> Install-Package AutoMapper

کلید Enter را فشار دهید. به این وسیلهAutoMapper  نصب می شود و به صورت یک DLL به قسمت reference پروژه ی شما اضافه می شود و می توانیم به راحتی از آن استفاده کنیم.

AutoMapper  در عمل چگونه کار می کند؟

ابتدا یک برنامه MVC  ایجاد می کنیم. در فایل ضمیمه ای که به همراه مقاله در اختیار شما گذاشته شده است، یک برنامه هم قرار دارد که بدون AutoMapper  کار می کند.

حالا بیایید همه ی Action های Controller  ها را یکی یکی ارزیابی کنیم و code  را با استفاده از AutoMapper دوباره بازنویسی کنیم.

مرحله 1 : یک پایگاه داده برای برنامه ایجاد کنید. فایل  Script  پایگاه داده در فایل ضمیمه موجود است.

برنامه ای که در فایل ضمیمه وجود دارد را در برنامه Visual Studio باز کنید.

همانطور که می بینید AutoMapper در پروژه ، reference داده شده است. حالا از فضای نام AutoMapper مطابق شکل زیر استفاده می کنیم :

مرحله 2 : Index Action

در Index Action در قسمت MyController (که در پوشه Controllers قرار دارد) ، کد زیر قرار دارد:

public ActionResult Index()
{
    var dbContext = new MyDBDataContext();
    var userList = from user in dbContext.Users select user;
    var users = new List<LearningMVC.Models.User>();
    if (userList.Any())
    {
        foreach (var user in userList)
        {
            users.Add(new LearningMVC.Models.User()
                {
                    UserId = user.UserId, 
                    Address = user.Address, 
                    Company = user.Company, 
                    FirstName = user.FirstName,
                    LastName = user.LastName,
                    Designation = user.Designation,
                    EMail = user.EMail, 
                    PhoneNo = user.PhoneNo
                });
        }
    }
  
    return View(users);
}

در این کد ، AutoMapper کجا قرار می گیرد؟ AutoMapper باید در جایی قرار بگیرد که بتواند Map کردن همه Property ها را انجام بدهد. بنابراین باید در سطر اول این کد، AutoMapper را تعریف کنیم.

یک mapping پیش فرض ، با نام "Mapper.CreateMap<T1, T2>()"  با نوع های داده ای مناسب ایجاد می کنیم. در این مورد ، T1 ، همان "LearningMVC.User" و T2 نیز همان "LearningMVC.Models.User" خواهد بود.

Mapper.CreateMap<LearningMVC.User, LearningMVC.Models.User>();
LearningMVC.User -> DTO Object Class
LearningMVC.Models.User -> Model Class to bind the View

در اینجا ما یک mapping بین DTO و یک Model class ، با استفاده از کلاس AutoMapper ایجاد می کنیم.

کد زیر را در داخل حلقه foreach قرار بدهید.

LearningMVC.Models.User userModel = Mapper.Map<LearningMVC.User, LearningMVC.Models.User>(user);

users.Add(userModel);

در مرحله ی آخر، باید Mapper.Map<T1, T2>(obj1) را فراخوانی کنیم تا شی T2 که map شده است را به ما برگرداند.

کد نهایی ما به صورت زیر خواهد بود :

public ActionResult Index()
{
    Mapper.CreateMap<LearningMVC.User, LearningMVC.Models.User>();
    var dbContext = new MyDBDataContext();
    var userList = from user in dbContext.Users select user;
    var users = new List<LearningMVC.Models.User>();
    if (userList.Any())
    {	
        foreach (var user in userList)
        {
            LearningMVC.Models.User userModel = Mapper.Map<LearningMVC.User, LearningMVC.Models.User>(user);
            users.Add(userModel);
        }
    }
  
    return View(users);

}

به وسیله این کار ، ما از کار خسته کننده وصل کردن Property ها به هم رهایی پیدا کردیم. حالا برنامه را اجرا کنید. می بینید که برنامه به درستی کار می کند.

مرحله 3 : Details Action (بخش جزئیات)

کدی که در حال حاضر داریم :

public ActionResult Details(int? id)
{
    var dbContext = new MyDBDataContext();
    var userDetails = dbContext.Users.FirstOrDefault(userId => userId.UserId == id);
    var user = new LearningMVC.Models.User();
    if (userDetails != null)
    {
        user.UserId = userDetails.UserId;
        user.FirstName = userDetails.FirstName;
        user.LastName = userDetails.LastName;
        user.Address = userDetails.Address;
        user.PhoneNo = userDetails.PhoneNo;
        user.EMail = userDetails.EMail;
        user.Company = userDetails.Company;
        user.Designation = userDetails.Designation;
    }
    return View(user);
{

کد جدیدی که با استفاده ازAutoMapper  کار می کند:

public ActionResult Details(int? id)
{
    var dbContext = new MyDBDataContext();
    Mapper.CreateMap<LearningMVC.User, LearningMVC.Models.User>();
    var userDetails = dbContext.Users.FirstOrDefault(userId => userId.UserId == id);
    LearningMVC.Models.User user = Mapper.Map<LearningMVC.User, LearningMVC.Models.User>(userDetails);
    return View(user);
}

مرحله 4 :  Create Action(بخش ایجاد یک کاربر جدید)

                کدی که در حال حاضر داریم :

[HttpPost]
public ActionResult Create(LearningMVC.Models.User userDetails)
{
    try
    {
        var dbContext = new MyDBDataContext();
        var user = new User();
        if (userDetails != null)
        {
            user.UserId = userDetails.UserId;
            user.FirstName = userDetails.FirstName;
            user.LastName = userDetails.LastName;
            user.Address = userDetails.Address;
            user.PhoneNo = userDetails.PhoneNo;
            user.EMail = userDetails.EMail;
            user.Company = userDetails.Company;
            user.Designation = userDetails.Designation;
        }
        dbContext.Users.InsertOnSubmit(user);
        dbContext.SubmitChanges();
        return RedirectToAction("Index");
    }
    catch
    {
        return View();
    }
} 

کد جدیدی که با استفاده از AutoMapper  کار می کند :

[HttpPost]
public ActionResult Create(LearningMVC.Models.User userDetails)
{
    try
    {
        Mapper.CreateMap<LearningMVC.Models.User, LearningMVC.User>();
        var dbContext = new MyDBDataContext();
        var user = Mapper.Map<LearningMVC.Models.User, LearningMVC.User>(userDetails);
        dbContext.Users.InsertOnSubmit(user);
        dbContext.SubmitChanges();
        return RedirectToAction("Index");
    }
    catch
    {
        return View();
    }
} 

در این کد ها ما با استفاده از mapping  ، کارهای مربوط به جابجایی را انجام دادیم. زیرا برای ایجاد Create Action، نیاز داریم که داده ها را از Model بخوانیم و آن ها را به DTO متصل کنیم .در این کد ها T1 مدل ما است و T2 نیز به منزله DTO است.

مرحله 5 : Edit Action (بخش مربوط به ویرایش )

کدی که در حال حاضر داریم :

public ActionResult Edit(int? id)
{
    var dbContext = new MyDBDataContext();
    var userDetails = dbContext.Users.FirstOrDefault(userId => userId.UserId == id);
    var user = new LearningMVC.Models.User();
    if (userDetails != null)
    {	
        user.UserId = userDetails.UserId;
        user.FirstName = userDetails.FirstName;
        user.LastName = userDetails.LastName;
        user.Address = userDetails.Address;
        user.PhoneNo = userDetails.PhoneNo;
        user.EMail = userDetails.EMail;
        user.Company = userDetails.Company;
        user.Designation = userDetails.Designation;
    }
    return View(user);
}

کد جدیدی که با استفاده از AutoMapper  کار می کند :

public ActionResult Edit(int? id)
{
    Mapper.CreateMap<LearningMVC.User, LearningMVC.Models.User>();
    var dbContext = new MyDBDataContext();
    var userDetails = dbContext.Users.FirstOrDefault(userId => userId.UserId == id);
    var user = Mapper.Map<LearningMVC.User, LearningMVC.Models.User>(userDetails)
    return View(user);
}

مرحله 6 : Delete Action (بخش مربوط به حذف)

کدی که در حال حاضر داریم :

public ActionResult Delete(int? id)
{
    var dbContext = new MyDBDataContext();
    var user = new LearningMVC.Models.User();
    var userDetails = dbContext.Users.FirstOrDefault(userId => userId.UserId == id);
    if (userDetails != null)
    {
        user.FirstName = userDetails.FirstName;
        user.LastName = userDetails.LastName;
        user.Address = userDetails.Address;
        user.PhoneNo = userDetails.PhoneNo;
        user.EMail = userDetails.EMail;
        user.Company = userDetails.Company;
        user.Designation = userDetails.Designation;
    }
    return View(user);
}

کد جدیدی که با استفاده از AutoMapper  کار می کند :

public ActionResult Delete(int? id)
{
    var dbContext = new MyDBDataContext();
    Mapper.CreateMap<LearningMVC.User, LearningMVC.Models.User>();
    var userDetails = dbContext.Users.FirstOrDefault(userId => userId.UserId == id);
    var user = Mapper.Map<LearningMVC.User, LearningMVC.Models.User>(userDetails);
    return View(user);
}

ForMember() و MapFrom() در AutoMapper

دو تابع مهمی که در AutoMapper وجود دارند و نقش مهمی در object mapping ایجاد می کنند ، دو تابع ForMember() و MapFrom() هستند. برای درک بهتر کارایی آن ها یک مثال میزنم. فرض کنید کلاس model/viewmodel یک Property به نام FullName دارد و ما می خواهیم FirstName (نام) و Last Name (نام خانوادگی) کاربر را از DTO بگیریم و به model متصل کنیم. برای از بین بردن این پیچیدگی و کار زیاد، از ForMember() و MapFrom() استفاده می کنیم. کد زیر را ببینید:

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

در این تکه کد می گوییم: ForMember FullName در بخش model class ما ، Property های FirstName و LastName را از map,DTO می کند.

کد، خودش به تنهایی بیانگر عملکردی که انجام می دهد، است.این نوع Custom Mapping ، mapping نامیده می شود.

آموزش asp.net mvc

فایل های ضمیمه

برنامه نویسان

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

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

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