从id加载对象的表作为外键

时间:2017-11-16 11:34:55

标签: c# entity-framework asp.net-core

我已将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吗?

感谢您的任何建议。

2 个答案:

答案 0 :(得分:2)

您使用实体框架标记了您的问题,但为了以防万一,我还将介绍实体框架核心,因为它们在此方面略有不同。

实体框架支持延迟加载,但重要的是,该属性必须为virtual才能启用,即:

public virtual Role UserRole { get; set; }

EF通过派生动态"代理"添加了延迟加载属性所需的逻辑。来自您的实体的类并覆盖该属性。由于无法覆盖非virtual属性,因此不会将此逻辑添加到没有virtual的属性中。如果没有virtual,导航属性将不会自动加载,并且将保持null,无论数据库中是否存在关联。

实体框架核心不支持所有的延迟加载,因此添加virtual对您没有帮助。

在任何一种情况下,你都应该真正地渴望加载。这是通过向您的查询添加Include来完成的。但是,你有两个问题:

  1. UserManager<TUser>不支持包含相关实体。您需要使用DbSet,即context.Users

  2. 您不能将IncludeFind(或任何与Find相关的方法)一起使用,因为它具有与连接不兼容的逻辑。也就是说,如果可能的话,Find尝试从上下文缓存中提取实体而根本不进行查询,因此,不能保证可以包括导航属性。因此,您必须切换到SingleOrDefault

  3. 之类的内容

    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);