AutoMapper 5.2.0 VIewModel到Core MVC中的Model问题

时间:2016-12-05 19:34:13

标签: c# asp.net-core asp.net-core-mvc automapper-5

型号:

 public class Client{
    public int Id {get;set;}

    public string Name {get;set;}

    public Address Address {get;set;}

    public int AddressId  {get;set;}
}

public class Address{
   public int Id

   public string Address1 {get;set;}

   public string PostCode {get;set;}
}

查看模特:

public class ClientViewNodel{
        public int Id {get;set;}

        public string Name {get;set;}

        public Address Address {get;set;}

        public int AddressId  {get;set;}
    }

    public class AddressViewModel{
       public int Id

       public string Address1 {get;set;}

       public string PostCode {get;set;}
    }

映射:

 Mapper.Initialize(config =>
    {
        config.CreateMap<ClientViewModel, Client>().ReverseMap();
        config.CreateMap<AddressViewModel, Address>().ReverseMap();
    });

控制器更新操作:

[HttpPost]
public async Task<IActionResult> Update(cLIENTViewModel viewModel)
{
    if (!ModelState.IsValid)
    {
        return View("Client",viewModel);
    }

    var client= _clientRepository.GetClient(viewModel.Id);
    if (client == null) 
        return NotFound();

    client= Mapper.Map<ClientViewModel, Client>(viewModel);

    _clientRepository.Update(client);
    var result = await _clientRepository.SaveChangesAsync();

    if (result.Success)
    {
        return RedirectToAction("Index");
    }

    ModelState.AddModelError("", result.Message);

    return View("Client",viewModel);
}

问题是当调用_clientRepository.Update(client)时,我收到一条错误消息:

  

无法跟踪实体类型“客户端”的实例,因为已经跟踪了具有相同密钥的此类型的另一个实例。添加新实体时,对于大多数密钥类型,如果未设置密钥,则将创建唯一的临时密钥值(即,如果为密钥属性指定了其类型的默认值)。如果要为新实体显式设置键值,请确保它们不会与现有实体或为其他新实体生成的临时值发生冲突。附加现有实体时,请确保只有一个具有给定键值的实体实例附加到上下文。

当我调试代码时,我可以看到当我将viewModel映射到模型时,客户端模型中的AddressID被设置为0.我猜这是导致问题。

如何将viewModel映射回模型,其中将更新地址的详细信息,例如Address1和Postcode,而不是Id。

我还试图在.ForMember(x => x.AddressId, opt => opt.Ignore())

的映射中忽略地址Id的映射

但它仍然将AddressId设置为0.

我错过了什么?

1 个答案:

答案 0 :(得分:3)

执行Mapper.Map<ClientViewModel, Client>(viewModel)时,AutoMapper会创建一个新的Client对象,其ID与现有Client对象的ID相同。

然后,您指示EntityFramework更新此对象图。实体框架不跟踪您的新客户端对象,因此它将对象附加到其内部魔术缓存/跟踪酱。由于ID的冲突,这会失败。因此,错误“无法跟踪实体类型'客户'的实例,因为已经跟踪了具有相同密钥的此类型的另一个实例”。

这也是0 AddressId的来源。 Address对象也是一个由AutoMapper创建的全新对象,该属性的值为default(int),因为AutoMapper创建后它从未被赋予其他值。