AutoMapper映射异常:User实体FirstName字段未成功映射排查
问题:AutoMapper映射UserForRegistrationDto到User实体时,FirstName字段未写入数据库
相关代码
User实体
namespace Pharma.Models { public partial class User { public int UserId { get; set; } public string FirstName { get; set; } public string Email { get; set; } public bool Active { get; set; } public User() { if (FirstName == null) { FirstName = ""; } if (Email == null) { Email = ""; } } } }
UserForRegistrationDto
namespace Pharma.DTOs { public partial class UserForRegistrationDto { public string Email { get; set; } public string Password { get; set; } public string PasswordConfirm { get; set; } public string FirstName { get; set; } public UserForRegistrationDto() { if (Email == null) { Email = ""; } if (Password == null) { Password = ""; } if (PasswordConfirm == null) { PasswordConfirm = ""; } if (FirstName == null) { FirstName = ""; } } } }
AuthController映射与注册逻辑
public class AuthController { private readonly AuthHelper _authHelper; IAuthRepository _authRepository; IUserRepository _userRepository; IMapper _mapper; public AuthController(IConfiguration config, IAuthRepository authRepository, IUserRepository userRepository) { _authHelper = new AuthHelper(config); _authRepository = authRepository; _userRepository = userRepository; _mapper = new Mapper(new MapperConfiguration(cfg => { cfg.CreateMap<UserForRegistrationDto, User>(); })); } [HttpPost("Register")] public async void RegisterAsync(UserForRegistrationDto userForRegistration) { byte[] passwordSalt = new byte[128 / 8]; // 检查密码与确认密码是否一致 if (userForRegistration.Password != userForRegistration.PasswordConfirm) { throw new Exception("Incorrect credentials!"); } // 检查邮箱是否已存在 if (await _authHelper.DoesUserExistByEmailAsync(userForRegistration.Email!)) { throw new Exception("User already exists!"); } _authHelper.GetPasswordHash(userForRegistration.Password, passwordSalt); byte[] passwordHash = []; byte[] passwordHashed = _authHelper.GetPasswordHash(userForRegistration.Password, passwordSalt); string EmailForRegister = userForRegistration.Email; List<SqlParameter> sqlParameters = new List<SqlParameter>(); SqlParameter passwordSaltParameter = new SqlParameter("@PasswordSalt", SqlDbType.VarBinary); passwordSaltParameter.Value = passwordSalt; SqlParameter passwordHashParameter = new SqlParameter("@PasswordHash", SqlDbType.VarBinary); passwordHashParameter.Value = passwordHash; sqlParameters.Add(passwordSaltParameter); sqlParameters.Add(passwordHashParameter); Console.WriteLine(sqlParameters); UserToRegisterAuthDto userToRegisterAuthDto = new UserToRegisterAuthDto { Email = EmailForRegister, passwordHash = passwordHashed, passwordSalt = passwordSalt }; _authRepository.AddEntity<UserToRegisterAuthDto>(userToRegisterAuthDto); User userDb = _mapper.Map<User>(userForRegistration); _userRepository.AddEntity<User>(userDb); _userRepository.SaveChanges(); _authRepository.SaveChanges(); } }
DataContext配置
using Microsoft.EntityFrameworkCore; using Pharma.Models; namespace Pharma.Data { public class DataContextEF : DbContext { private readonly IConfiguration _config; public DataContextEF(IConfiguration config) { _config = config; } public virtual DbSet<User> Users { get; set; } public virtual DbSet<Substance> Substances { get; set; } public virtual DbSet<Dosage> Dosages { get; set; } public virtual DbSet<Product> Products { get; set; } public virtual DbSet<UserToRegisterAuthDto> UsersAuth { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { if (!optionsBuilder.IsConfigured) { optionsBuilder .UseSqlServer(_config.GetConnectionString("DefaultConnection"), optionsBuilder => optionsBuilder.EnableRetryOnFailure()); } } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.HasDefaultSchema("dbo"); modelBuilder.Entity<User>() .ToTable("Users", "dbo") .HasKey(u => u.UserId); modelBuilder.Entity<Substance>() .ToTable("Substances", "dbo") .HasKey(u => u.SubstanceId); modelBuilder.Entity<Dosage>() .ToTable("Dosages", "dbo") .HasKey(u => u.DosageId); modelBuilder.Entity<Product>() .ToTable("Products", "dbo") .HasKey(u => u.ProductId); modelBuilder.Entity<UserToRegisterAuthDto>() .ToTable("Auth2", "dbo") .HasKey(u => u.Email); } } }
问题排查与解决方案
1. 先确认请求数据是否包含FirstName
在RegisterAsync方法开头加调试代码,检查前端传入的Dto里FirstName是否有值:
// 调试输出,确认接收的FirstName内容 Console.WriteLine($"Received FirstName: {userForRegistration.FirstName}");
如果输出为空,说明前端没传这个字段,先修复请求数据;如果有值,再往下排查。
2. 修正AutoMapper初始化方式
你现在手动在控制器里创建Mapper实例的方式不规范,容易导致映射规则加载异常。正确做法是用依赖注入:
- 在Program.cs/Startup.cs注册AutoMapper:
// 扫描所有包含映射配置的程序集 builder.Services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()); - 修改控制器构造函数,注入IMapper:
public AuthController(IConfiguration config, IAuthRepository authRepository, IUserRepository userRepository, IMapper mapper) { _authHelper = new AuthHelper(config); _authRepository = authRepository; _userRepository = userRepository; _mapper = mapper; // 使用注入的实例,不再手动创建 } - (可选)创建独立的映射配置类:
新建一个配置类让AutoMapper明确加载映射规则:namespace Pharma.Mappings { public class UserMappingProfile : Profile { public UserMappingProfile() { // 显式声明映射,避免自动映射失效 CreateMap<UserForRegistrationDto, User>() .ForMember(dest => dest.FirstName, opt => opt.MapFrom(src => src.FirstName)) .ForMember(dest => dest.Email, opt => opt.MapFrom(src => src.Email)); } } }
3. 检查User实体的Active字段默认值
User实体的Active字段没有默认值,映射后的User对象中Active是默认的false,如果数据库该字段要求非空且无默认值,可能影响其他字段写入。可以在构造函数里给Active加默认值:
public User() { FirstName = FirstName ?? ""; Email = Email ?? ""; Active = false; // 显式设置默认值 }
总结
最可能的原因是AutoMapper初始化方式错误导致自动映射规则未生效,其次是前端请求未传递FirstName字段。按照上述步骤逐一排查,即可解决问题。
内容的提问来源于stack exchange,提问作者user23278485
相关产品推荐
相关产品推荐

