使用 AutoMapper 映射两个模型
Posted
技术标签:
【中文标题】使用 AutoMapper 映射两个模型【英文标题】:Mapping two models with AutoMapper 【发布时间】:2021-12-23 01:57:35 【问题描述】:我有一个 Customer 模型,它与 Address 模型具有一对一的关系。我正在使用 AutoMapper 来映射这些值。我想使用我的 API 在数据库中创建一个新客户,理想情况下,它将根据提供给客户模型的信息插入一个新地址行。
这是我收到的实体框架核心的 SQL 异常:
---> Microsoft.Data.SqlClient.SqlException (0x80131904): Cannot insert the value NULL into column 'AddressId', table 'dbo.Customers'; column does not allow nulls. INSERT fails.
注意 - BaseEntity 仅包含 ID、并发检查等常见属性
客户模型:
public class Customer : BaseEntity
public string FirstName get; set;
public string LastName get; set;
public string Phone get; set;
public string Email get; set;
public string UpdatedBy get; set;
public DateTime? LastContact get; set;
#region Navigation Properties
public int? AddressId get; set;
public string UserId get; set;
public User User get; set;
public virtual Address Address get; set;
public virtual ICollection<Invoice> Invoices get; set;
#endregion
我的地址模型:
public class Address : BaseEntity
public string AddressLine1 get; set;
public string AddressLine2 get; set;
public string City get; set;
public string State get; set;
public string PostalCode get; set;
#region Navigation Properties
public virtual Customer Customer get; set;
#endregion
我对请求使用了一个 DTO 类,如下:
public class CustomerCreateDto
public string FirstName get; set;
public string LastName get; set;
public string Phone get; set;
public string Email get; set;
public string AddressLine1 get; set;
public string AddressLine2 get; set;
public string City get; set;
public string State get; set;
public string PostalCode get; set;
public string UserId get; set;
AddressDto:
public class AddressDto : BaseEntity
[Required]
public string AddressLine1 get; set;
public string AddressLine2 get; set;
[Required]
public string City get; set;
public string State get; set;
[Required]
[DataType(DataType.PostalCode)]
public string PostalCode get; set;
CustomerDto
public class CustomerDto : BaseEntity
public string FirstName get; set;
public string LastName get; set;
public string Phone get; set;
public string Email get; set;
public string UserId get; set;
public int AddressId get; set;
public string UpdatedBy get; set;
public DateTime? LastContact get; set;
public virtual UserDto User get; set;
public virtual AddressDto Address get; set;
public virtual ICollection<InvoiceDto> Invoices get; set;
这是 AutoMapper 的配置
public class MappingConfiguration : Profile
public MappingConfiguration()
CreateMap<AddressDto, Address>().ReverseMap();
CreateMap<CustomerDto, Customer>().ForMember(dst => dst.UserId,
opt => opt.MapFrom(src => src.User.Id)).ForMember(dst =>
dst.Address,
opt => opt.MapFrom(src => src.Address)).ReverseMap();
CreateMap<CustomerCreateDto, Customer>().ReverseMap();
这里是Controller方法。我知道我可以通过使用addressDto
对象(如customer.Address = address
)手动设置值来做到这一点,但我想看看是否有更好的方法
[HttpPost]
public async Task < IActionResult > Create([FromBody] CustomerCreateDto customerDto)
if (customerDto == null || !ModelState.IsValid)
return BadRequest(ModelState);
var addressDto = new AddressDto
AddressLine1 = customerDto.AddressLine1,
AddressLine2 = customerDto.AddressLine2,
City = customerDto.City,
State = customerDto.State,
PostalCode = customerDto.PostalCode,
CreatedDate = DateTime.Now,
;
var user = await _userManager.FindByIdAsync(customerDto.UserId);
var address = _mapper.Map<Address>(addressDto);
var customer = _mapper.Map<Customer>(customerDto);
customer.CreatedDate = DateTime.Now;
var result = await _customerRepository.CreateAsync(customer);
if (result) return Created("Created", new customer );
// if we got this far it means the request failed
return new
StatusCodeResult(StatusCodes.Status500InternalServerError);
【问题讨论】:
AutoMapper 将您的 DTO 映射到实体中,但它不知道如何填充导航属性。所以你必须创建并保存地址(_addressRepo.CreateAsync(address)
)并分配这个对象customer.Address = address
。您可以使用 AutoMapper 自动执行此操作,但代码有点讨厌
您可以添加导航。道具。进入 DTO。在映射器方面,您可以处理映射。
我没有看到CustomerCreateDto
的任何映射。同时,我看到CustomerDto
和AddressDto
的映射未在此处显示。那么问题/问题到底是什么?
我已经添加了这些
【参考方案1】:
我正在寻找的功能是通过将 CustomerCreateDto 更改为:
public class CustomerCreateDto
public string FirstName get; set;
public string LastName get; set;
public string Phone get; set;
public string Email get; set;
public string UserId get; set;
public virtual AddressDto Address get; set;
映射配置:
public class MappingConfiguration : Profile
public MappingConfiguration()
CreateMap<AddressDto, Address>().ReverseMap();
CreateMap<CustomerDto, Customer>().ForMember(dst => dst.UserId,
opt => opt.MapFrom(src => src.User.Id));
CreateMap<CustomerCreateDto, Customer>().ForMember(dst => dst.Address,
opt => opt.MapFrom(src => src.Address)).ReverseMap().ReverseMap();
我的控制器:
[HttpPost]
public async Task<IActionResult> Create([FromBody] CustomerCreateDto customerDto)
if (customerDto == null || !ModelState.IsValid)
return BadRequest(ModelState);
var customer = _mapper.Map<Customer>(customerDto);
customer.CreatedDate = DateTime.Now;
var result = await _customerRepository.CreateAsync(customer);
if (result) return Created("Created", new customer );
return new StatusCodeResult(StatusCodes.Status500InternalServerError);
【讨论】:
以上是关于使用 AutoMapper 映射两个模型的主要内容,如果未能解决你的问题,请参考以下文章