2

I'm trying to use ViewModels and AutoMapper, as I know these are best practice for avoiding lots of issues.

I'm ok using AutoMapper to populate a viewmodel, but I'm not as sure about how to update my database, from the ViewModel being posted back to my controller.

My GET is:

        public ActionResult Edit(int id = 0)
        {
        Customer customer = db.Customers.Find(id);
        var offers = db.Offers.Where(x => x.CustomerId == id).ToList();
        var email = db.Emails.FirstOrDefault();
        var vm = new CreateViewModel();

        vm.CustomerId = customer.CustomerId;
        vm.ArrivalDate = customer.ArrivalDate;
        vm.CustomerName = customer.CustomerName;
        vm.EmailAddress = customer.EmailAddress;
        vm.NumNights = customer.NumNights;
        vm.NumPeople = customer.NumPeople;

        vm.EmailBody = email.EmailBody;
        vm.From = email.From;
        vm.Subject = email.Subject;

        // Map list of Offers into ViewModel
        vm.Offers = Mapper.Map<IList<Offer>, IList<OfferVM>>(offers);
        return View(vm);
       }

My POST is:

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Edit(EditViewModel vme)
    {
        if (ModelState.IsValid)
        {
            // Update the Customer properties
            Customer customer = db.Customers.Find(vme.CustomerId);
            customer.NumPeople = vme.NumPeople;
            customer.NumNights = vme.NumNights;
            customer.ArrivalDate = vme.ArrivalDate;
            customer.CustomerName = vme.CustomerName;
            customer.EmailAddress = vme.EmailAddress;

            // Update Offers table
            foreach (var o in vme.Offers)
            {
                // find the offer 
                Offer offer = db.Offers.Find(o.OfferId);
                if (offer != null)
                {
                    // update the properties of Offer
                    offer.RoomRate = o.RoomRate;
                    offer.IncludeInOffer = o.IncludeInOffer;
                }
            }

            db.SaveChanges();

            return RedirectToAction("Index");
        }
        return View(vme);
    }

So my Post is manually updating two database tables (Offers and Customers).

The GET method is elegant, using AutoMapper, the POST is not. I'm wondering if there is a more straightforward way of updating the database via AutoMapper, without having to manually go through each property I am looking to update? Or is my POST controller as efficient as it can be?

Thank you for any pointers,

Mark

4

2 回答 2

5

There is an overload of Map that allows to map properties to one preexisting instance:

Mapper.Map<IObjectA, IObjectB>(objectA, ObjectB);

Thus, you just have to map from the parameter vme (CreateViewModel vme) to the customer recovered from the DB. This also applies to the offers part.

Of course, you'll have to configure the mappings in the reverse direction: you've done it from db objects to view model, and now you need to map them from viewmodel to db objects. If you've followed Automapper conventions it will be pretty easy or even unnnecessary.

EDIT: added interesting comment by Henk Mollema

You can configure AutoMapper to ignore properties, if your ViewModel doesn't contain all the properties from your domain model (which is most likely the case), it won't overwrite them with nulls.

于 2013-07-10T09:15:32.990 回答
1

You first need to define your mapping like this:

Mapper.CreateMap<EditViewModel, Customer>();

Your updated action method could look like this. What happens here is your action method receives your view model and checks its validity. If it is valid then it does the mapping from your view model to your domain model. This domain model is then passed to your service or repository layer to update the cusotmer in the database. How you update the record depends entirely on you.

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(EditViewModel viewModel)
{
     if (!ModelState.IsValid)
     {
          return View(viewModel);
     }

     Customer customer = Mapper.Map<Customer>(viewModel);

     customerService.Edit(customer);

     return RedirectToAction("List");
}

I hope this can help guide you in the right direction. Your HttpGet action method will work in a similar way.

于 2013-07-11T08:54:41.963 回答