我已将UserRole类型为User的用户定义为另一个表的foreing键。 Entiti框架自动将UserRole名称转换为UserRoleId,类型为整数(Id)。没关系。但我在表User table preview中有UserRoleId = 2 当我尝试通过Id获取用户时:
var user = await _userManager.FindByIdAsync(id);
所以参数UserRole为null user preview from debuging。
申请用户:
public class ApplicationUser : IdentityUser
{
public int PriorityLevel { get; set; }
public Role UserRole { get; set; }
public string ForName { get; set; }
public string LastName { get; set; }
public string Mobile { get; set; }
public string WorkPlace { get; set; }
public string Notice { get; set; }
}
我必须使用一些实体框架命令来加载UserRole作为类型Role吗?或者我可以从表中获取UserRoleId吗?
感谢您的任何建议。
答案 0 :(得分:2)
您使用实体框架标记了您的问题,但为了以防万一,我还将介绍实体框架核心,因为它们在此方面略有不同。
实体框架支持延迟加载,但重要的是,该属性必须为virtual
才能启用,即:
public virtual Role UserRole { get; set; }
EF通过派生动态"代理"添加了延迟加载属性所需的逻辑。来自您的实体的类并覆盖该属性。由于无法覆盖非virtual
属性,因此不会将此逻辑添加到没有virtual
的属性中。如果没有virtual
,导航属性将不会自动加载,并且将保持null
,无论数据库中是否存在关联。
实体框架核心不支持所有的延迟加载,因此添加virtual
对您没有帮助。
在任何一种情况下,你都应该真正地渴望加载。这是通过向您的查询添加Include
来完成的。但是,你有两个问题:
UserManager<TUser>
不支持包含相关实体。您需要使用DbSet
,即context.Users
。
您不能将Include
与Find
(或任何与Find
相关的方法)一起使用,因为它具有与连接不兼容的逻辑。也就是说,如果可能的话,Find
尝试从上下文缓存中提取实体而根本不进行查询,因此,不能保证可以包括导航属性。因此,您必须切换到SingleOrDefault
。
var user = await context.Users.Include(x => x.UserRole).SingleOrDefault(x => x.Id == id);
有了这个,UserRole
现在应该有一个值。
或者,您应该能够明确加载UserRole
:
var user = await _userManager.FindByIdAsync(id);
context.Entry(user).Reference(s => s.UserRole).Load();
这种方法在实体框架和实体框架核心中都是相同的。然而,它仅在1.1中引入EF Core,因此要认识到您正在运行的版本。这里的一个缺点是,这将导致(可能)两个查询。同样,由于Find
方法尝试从上下文缓存中检索,它可能您将在那里避免查询,但该实体不在缓存中,它将需要两个查询:一个用于用户,一个用于相关角色。但是,懒惰加载也是如此。只有热切加载才允许使用JOIN
s组合查询。
答案 1 :(得分:1)
您可以使用此方法获取用户的所有角色。
_userManager.GetRolesAsync(id);