ASP.NET Core 3.1:自定义IdentityUser的Settings被无关EF查询填充的疑问
问题原因解析
1. UserManager.GetUserAsync 不加载Settings的原因
UserManager<ApplicationUser> 的默认查询逻辑仅会加载 ApplicationUser 自身的标量属性(比如你定义的Name,以及IdentityUser自带的Id、UserName等),这些属性对应数据库AspNetUsers表中的直接字段,所以查询时会直接读取填充。
而Settings是导航属性,对应关联的UserSettings表数据,Identity框架的默认查询并不会自动包含(Include)导航属性,因此调用GetUserAsync后,user.Settings只会保留你在默认构造函数里初始化的空实例,不会从数据库加载真实数据。
2. 查询UserSettings后自动填充的原因
这是EF Core的**关系修复(Relationship Fixup)**机制在起作用:
- 当你通过
_applicationDbContext.UserSettings查询数据时,DbContext会将查询到的UserSettings实例加入自身的跟踪缓存。 - 之前通过
UserManager获取的user实例,已经被同一个DbContext实例跟踪(因为UserManager和控制器注入的是同一个DbContext)。 - EF Core会自动检查跟踪缓存中的实体关联,将匹配的
UserSettings实例赋值给user.Settings属性,因此你会看到该属性被自动填充。
解决方案
如果想直接通过GetUserAsync获取包含Settings的用户实例,可以通过以下方式实现:
- 自定义UserManager,手动Include导航属性
创建自定义UserManager,添加包含导航属性的查询方法:public class ApplicationUserManager : UserManager<ApplicationUser> { private readonly ApplicationDbContext _dbContext; public ApplicationUserManager(ApplicationDbContext dbContext, IUserStore<ApplicationUser> store, IOptions<IdentityOptions> optionsAccessor, IPasswordHasher<ApplicationUser> passwordHasher, IEnumerable<IUserValidator<ApplicationUser>> userValidators, IEnumerable<IPasswordValidator<ApplicationUser>> passwordValidators, ILookupNormalizer keyNormalizer, IdentityErrorDescriber errors, IServiceProvider services, ILogger<UserManager<ApplicationUser>> logger) : base(store, optionsAccessor, passwordHasher, userValidators, passwordValidators, keyNormalizer, errors, services, logger) { _dbContext = dbContext; } public async Task<ApplicationUser> GetUserWithSettingsAsync(ClaimsPrincipal principal) { var userId = GetUserId(principal); return await _dbContext.Users.Include(u => u.Settings).SingleOrDefaultAsync(u => u.Id == userId); } } - 开启延迟加载
将Settings属性改为virtual,同时在DbContext配置中启用延迟加载代理:
开启后,当你首次访问// 修改ApplicationUser类 public virtual UserSettings Settings { get; set; } = new UserSettings(); // 配置DbContext时启用延迟加载 services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(connectionString) .UseLazyLoadingProxies());user.Settings时,EF Core会自动从数据库加载关联数据。
内容的提问来源于stack exchange,提问作者dpant
相关产品推荐
相关产品推荐

