3

楷模:

 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。

我还尝试在映射中忽略 Id for Address 的映射.ForMember(x => x.AddressId, opt => opt.Ignore())

但它仍然将 AddressId 设置为 0。

我错过了什么?

4

1 回答 1

3

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

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

这也是0AddressId 的来源。Address 对象也是一个全新的对象,由 AutoMapper 创建,并且该属性具有 value default(int),因为 AutoMapper 在创建后从未为其分配另一个值。

于 2016-12-05T20:06:13.283 回答