Asp.net mvc AutoMapper展平用于查看记录,但不用于创建/更新?

Asp.net mvc AutoMapper展平用于查看记录,但不用于创建/更新?,asp.net-mvc,entity-framework,automapper,Asp.net Mvc,Entity Framework,Automapper,我有一个与地址模型有一对一关系的公司模型。我正在使用视图模型进行创建、详细信息、编辑和更新操作。我使用AutoMapper从一个模型映射到另一个视图模型,反之亦然 我的视图模型用于包含公开公司地址的属性: public Address Address { get; set; } 我最近更改了此选项,以抽象地址数据并对地址的某些属性进行验证(有关更多信息,请参阅my…) 在这些更改之后,我的属性如下: public string Address1 { get; set; } public str

我有一个与地址模型有一对一关系的公司模型。我正在使用视图模型进行创建、详细信息、编辑和更新操作。我使用AutoMapper从一个模型映射到另一个视图模型,反之亦然

我的视图模型用于包含公开公司地址的属性:

public Address Address { get; set; }
我最近更改了此选项,以抽象地址数据并对地址的某些属性进行验证(有关更多信息,请参阅my…)

在这些更改之后,我的属性如下:

public string Address1 { get; set; }
public string Address2 { get; set; }
public string City { get; set; }
// etc...
这弄坏了我的汽车制造商。基于对我另一个问题的回答,我决定使用AutoMapper的扁平化功能。我更改了属性名称,以符合Navigation_propertyProperty的命名约定:

public string AddressAddress1 { get; set; }
public string AddressAddress2 { get; set; }
public string AddressCity { get; set; }
// etc...
我修改了我的视图以使用这些新的属性名称,并且成功了!嗯,有点。如果我查看一家公司的详细信息,我可以看到它的地址。如果我删除一家公司,地址也会被成功删除。但是,在编辑时,会保存我更改的公司属性,但不会保存地址属性。如果我创建了一个新公司,那么它创建时没有地址

因此,似乎AutoMapper正在工作(它能够提取现有公司的地址),但更新没有进入数据库。。。如果我手动将视图模型属性映射到company.Address属性,它可以工作,但我不知道如何使用AutoMapper使其工作

我是否需要改变我在控制器中保存数据的方式,告诉上下文具体更新地址或其他什么

以下是我的控制器的编辑方法供参考:

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);
}
公共操作结果编辑(int-id=0) { 公司=数据库公司 .包括(c=>c.地址) .其中(c=>c.CompanyID==id) .Single(); //确保我们找到了什么 如果(公司==null) 返回HttpNotFound(); //使用AutoMapper将模型映射到viewmodel CompanyViewModel viewModel=Mapper.Map(公司); 返回视图(viewModel); } [HttpPost] [ValidateAntiForgeryToken] 公共操作结果编辑(公司视图模型视图模型) { if(ModelState.IsValid) { //在数据库中找到合适的记录 公司=数据库公司 .包括(c=>c.地址) .Where(c=>c.CompanyID==viewModel.CompanyID) .Single(); //将viewmodel数据映射到公司对象 Mapper.Map(viewModel,公司); //我还尝试了以下方法,但没有成功: //Mapper.Map(viewModel,公司); //company=Mapper.Map(viewModel,company); //保存并重定向到公司列表 db.SaveChanges(); 返回操作(“索引”); } 返回视图(viewModel); }
感谢您的帮助。如前所述,我总是可以手动将视图模型映射到要更新/创建的对象(事实上,有些人会认为这通常是写入DB的更好做法),但我很好奇为什么映射只能在一个方向上工作……请告诉我您是否需要更多代码……

老实说,我不确定,为什么这在某些场景下不起作用,现在你已经改变了一切,我不想告诉你全部撤销,但在这种情况下,定制地图通常更容易:

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.
        }));
AutoMapper.Mapper.CreateMap()
.FormMember(dest=>dest.Address1,opts=>opts.MapFrom(src=>src.Address.Address1))
.FormMember(dest=>dest.Address1,opts=>opts.MapFrom(src=>src.Address.Address1))
//等等。
.ForMember(dest=>dest.Country,opts=>opts.MapFrom(src=>src.Address.Country));
AutoMapper.Mapper.CreateMap()
.ForMember(dest=>dest.Address,opts=>opts.MapFrom(src=>newaddress
{
Address1=src.Address1,
Address2=src.Address2,
//等等。
}));

这似乎很多,但您只需要为应用程序指定一次,然后就可以开始了。现在可能对你没有帮助,但将来…

我不介意像这样定制地图(实际上可能更喜欢知道地图布局正确,而不是由AutoMapper“神奇地”决定),但我很好奇为什么我的更新不起作用!因此,对我先前问题的评论证实了这是正确的解决方案——显然,扁平化不会自动反向工作。我继续按照这里所示定义了我的地图,这让我1)有了更高的舒适度,事情将被正确地映射,2)摆脱了ViewModel中的时髦属性名称(Address1)。谢谢,+1!