0

I have a Company model that has a one-to-one relationship with an Address model. I am using a view model for my create, detail, edit, and update actions. I am using AutoMapper to map from model to view model and vice versa.

My view model used to contain a property exposing the Company's Address:

public Address Address { get; set; }

I recently changed this to abstract the Address data and achieve validation on some properties of the address (See my related question here for more info...)

After those changes, I had properties like:

public string Address1 { get; set; }
public string Address2 { get; set; }
public string City { get; set; }
// etc...

This broke my AutoMapper. Based on the answer to my other question, I decided to use the flattening feature of AutoMapper. I changed my property names to match the naming convention of Navigation_propertyProperty:

public string AddressAddress1 { get; set; }
public string AddressAddress2 { get; set; }
public string AddressCity { get; set; }
// etc...

I modified my views to use these new property names, and it worked! Well, sort of. If I view the details of a company, I can see its address. If I delete a company, the address is successfully deleted as well. However, on an edit, company properties I change are saved but address properties are not. If I create a new company, it is created without an address.

So it seems the AutoMapper is working (it is able to pull the address for existing companies) but updates are not making it into the database... If I manually map the view model properties to the company.Address properties it works, but I can't figure out how to get this to work with AutoMapper.

Do I need to change the way I am saving the data in the controller, by telling the context to specifically update the address or something?

Here's my controller's Edit methods for reference:

public ActionResult Edit(int id = 0)
{
    Company company = db.Companies
        .Include(c => c.Address)
        .Where(c => c.CompanyID == id)
        .Single();

    // Make sure we found something
    if (company == null)
        return HttpNotFound();

    // Use AutoMapper to map model to viewmodel
    CompanyViewModel viewModel = Mapper.Map<Company, CompanyViewModel>(company);

    return View(viewModel);
}


[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(CompanyViewModel viewModel)
{
    if (ModelState.IsValid)
    {
        // Find appropriate record in DB
        Company company = db.Companies
            .Include(c => c.Address)
            .Where(c => c.CompanyID == viewModel.CompanyID)
            .Single();

        // Map viewmodel data to company object
        Mapper.Map<CompanyViewModel, Company>(viewModel, company);

        // I've also tried the following without success:
        // Mapper.Map(viewModel, company);
        // company = Mapper.Map<CompanyViewModel, Company>(viewModel, company);

        // Save and redirect to company list
        db.SaveChanges();
        return RedirectToAction("Index");
    }

    return View(viewModel);
}

Any help is appreciated. As mentioned, I can always manually map from the view model to the object to update/create (indeed, some would argue that's a better practice for writing to the DB in general) but I am curious as to why the mapping works in one direction only...Please let me know if you need more code...

4

1 回答 1

2

老实说,我不确定为什么这仅在某些情况下不起作用,现在您已经更改了所有内容,我不想告诉您全部撤消,但是在这种情况下,通常更容易自定义您的地图:

AutoMapper.Mapper.CreateMap<Company, CompanyViewModel>()
    .ForMember(dest => dest.Address1, opts => opts.MapFrom(src => src.Address.Address1))
    .ForMember(dest => dest.Address1, opts => opts.MapFrom(src => src.Address.Address1))
    // etc.
    .ForMember(dest => dest.Country, opts => opts.MapFrom(src => src.Address.Country));

AutoMapper.Mapper.CreateMap<CompanyViewModel, Company>()
    .ForMember(dest => dest.Address, opts => opts.MapFrom(src => new Address
        {
            Address1 = src.Address1,
            Address2 = src.Address2,
            // etc.
        }));

看起来很多,但您只需为您的应用程序指定一次,然后您就可以开始了。现在可能对你没有帮助,但在未来......

于 2013-10-03T18:52:35.933 回答