自定义AppUserStore移除单个外部登录时全部被删除的问题求助
问题分析与解决方案
嘿,我来帮你排查这个移除单个外部登录却误删所有记录的问题!
首先咱们先揪出代码里的问题根源:你用DataContext.Entry(user).Entity.AppUserLogins来操作导航集合的写法,其实绕开了EF实体跟踪的正常逻辑,很容易触发意外的批量删除。
为什么会删光所有外部登录?
当你通过Entry(user).Entity访问AppUserLogins时,要么是这个导航集合没有被正确加载(比如没开延迟加载,也没预先用Include加载),导致EF无法精准识别要删除的单个条目;要么是这种直接操作Entry.Entity的方式,让EF的状态跟踪机制混乱,误把整个导航集合的所有条目都标记为Deleted状态,最终执行SaveChanges时就全删了。
两种靠谱的修复方案
方案一:正确加载导航集合后操作实体本身
先确保AppUserLogins被加载,然后直接通过传入的user实体的导航集合移除目标条目,这是符合EF跟踪逻辑的标准写法:
async Task IUserLoginStore<AppUser, int>.RemoveLoginAsync(AppUser user, UserLoginInfo login) { // 检查导航集合是否已加载,未加载则手动触发加载 if (!DataContext.Entry(user).Collection(u => u.AppUserLogins).IsLoaded) { await DataContext.Entry(user).Collection(u => u.AppUserLogins).LoadAsync(); } var externalLogin = user.AppUserLogins.FirstOrDefault(l => l.LoginProvider == login.LoginProvider && l.ProviderKey == login.ProviderKey); if (externalLogin != null) { user.AppUserLogins.Remove(externalLogin); } await DataContext.SaveChangesAsync(); }
方案二:直接操作DbSet删除目标记录
这种方式更直接,跳过导航集合的加载问题,直接从数据库上下文的AppUserLogins集合中定位并删除目标记录:
async Task IUserLoginStore<AppUser, int>.RemoveLoginAsync(AppUser user, UserLoginInfo login) { var externalLogin = DataContext.AppUserLogins.FirstOrDefault(l => l.UserId == user.Id && l.LoginProvider == login.LoginProvider && l.ProviderKey == login.ProviderKey); if (externalLogin != null) { DataContext.AppUserLogins.Remove(externalLogin); } await DataContext.SaveChangesAsync(); }
额外小提醒
- 如果你用的是EF Core,确保延迟加载已开启(或者在需要的时候手动用
Include预加载导航属性),避免因导航集合为空导致的逻辑错误。 - 尽量避免直接通过
Entry(user).Entity操作导航属性,直接使用传入的user实体本身即可,EF会自动跟踪它的状态变化。
内容的提问来源于stack exchange,提问作者Tyler Durden
相关产品推荐
相关产品推荐

