Linq查询可显式加载相关数据

时间:2018-07-09 13:59:01

标签: c# linq entity-framework-core

我正在使用EF Core来处理预先存在的数据库。这是一个非常常见的模型,它使用很多联接表,具体针对我的情况,是usersroles的联接表。 UserRole表只有两列-UserIdRoleId

以下代码显示了我最近一次尝试将所有数据收集到一个DTO对象中的最新尝试,但有一个例外-我似乎无法加载与Roles相关的RoleId出现在UserRoles集合中。

关于如何加载关联的角色集合的任何建议?我将不得不遍历Role集合,以将角色的友好名称添加到用户声明中,而现在,我只是以一个大的胖null结尾。

var validatedUser = _context.User
                .Where(x => string.Equals(x.UserName, username, StringComparison.CurrentCultureIgnoreCase) && x.Active)
                .Include(x => x.UserRole)
                .ThenInclude(x => x.Role)
                .Select(result => new ValidatedUser
                {
                    Id = result.Id,
                    Email = result.Email,
                    FirstName = result.FirstName,
                    LastName = result.LastName,
                    PhoneNumber = result.PhoneNumber,
                    Username = result.UserName,
                    UserRoles = result.UserRole,
                    //Roles = result.Role, // this is where failure happens
                    PasswordHash = result.PasswordHash
                })
                .FirstOrDefault();

编辑1-显示UserRole的modelBuilder

modelBuilder.Entity<UserRole>(entity =>
{
    entity.HasKey(e => new { e.UserId, e.RoleId });
    entity.Property(e => e.UserId).HasColumnName("UserID");
    entity.Property(e => e.RoleId).HasColumnName("RoleID");
    entity.HasOne(d => d.Role)
        .WithMany(p => p.UserRole)
        .HasForeignKey(d => d.RoleId)
        .HasConstraintName("FK_UserRole_RoleID");
     entity.HasOne(d => d.User)
        .WithMany(p => p.UserRole)
        .HasForeignKey(d => d.UserId)
        .HasConstraintName("FK_UserRole_UserID");
});

这是ValidatedUser类:

public class ValidatedUser
{
    public Guid Id { get; set; }
    public string Username { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string PasswordHash { get; set; }
    public string FullName => $"{FirstName} {LastName}";
    public string Email { get; set; }
    public string PhoneNumber { get; set; }
    public string FormattedPhoneNumber
    {
        get
        {
            if (string.IsNullOrEmpty(PhoneNumber)) return PhoneNumber;

            switch (PhoneNumber.Length)
            {
                case 10:
                    return $"({PhoneNumber.Substring(0, 3)}) {PhoneNumber.Substring(3, 3)}-{PhoneNumber.Substring(6, 4)}";
                default:
                    return PhoneNumber;
            }
        }
    }

    public ICollection<UserRole> UserRoles { get; set; }
    public ICollection<Role> Roles { get; set; }
}

2 个答案:

答案 0 :(得分:1)

首先,不需要Include&ThenInclude语句,因为您正在执行将在服务器端进行评估的select语句。

对于查询,该怎么办?

var validatedUser = 
    _context.User
    .Where(x => string.Equals(x.UserName, username, StringComparison.CurrentCultureIgnoreCase) && x.Active)
    .Select(result => new ValidatedUser
    {
        Id = result.Id,
        Email = result.Email,
        FirstName = result.FirstName,
        LastName = result.LastName,
        PhoneNumber = result.PhoneNumber,
        Username = result.UserName,
        Roles = result.UserRoles.Select(ur => ur.Role),
        PasswordHash = result.PasswordHash
     }).FirstOrDefault();

如果这不起作用,您始终可以映射客户端角色(在这种情况下,您确实需要Include / thenInclude():

var validatedUser = 
    _context.User
    .Include(u => u.UserRoles).ThenInclude(ur => ur.Role)
    .Where(x => string.Equals(x.UserName, username, StringComparison.CurrentCultureIgnoreCase) && x.Active)
    .ToList() // Force execution of query here...
    .Select(result => new ValidatedUser // From here on it's client side
    {
        Id = result.Id,
        Email = result.Email,
        FirstName = result.FirstName,
        LastName = result.LastName,
        PhoneNumber = result.PhoneNumber,
        Username = result.UserName,
        UserRoles = result.UserRoles.ToList(),
        Roles = result.UserRoles.Select(ur => ur.Role).ToList(),
        PasswordHash = result.PasswordHash
     }).FirstOrDefault();

答案 1 :(得分:-1)

尝试一下, 昨天我回答了类似的问题。可能有帮助。

https://stackoverflow.com/a/51230593/8092001

这不是正确的方法,因为您已经有外键引用了该表,但是仍然会导致您的结果。

var validatedUser = (from user in _context.User.Where(x => string.Equals(x.UserName, username, StringComparison.CurrentCultureIgnoreCase) && x.Active)
                     join userRole in _context.UserRole
                     on user.Id equals userRole.UserId
                     join role in _context.Roles
                     on userRole.RoleId equals role.RoleId
                     select new {user,userRole,role})
                .Select(result => new ValidatedUser
                {
                    Id = result.user.Id,
                    Email = result.user.Email,
                    FirstName = result.user.FirstName,
                    LastName = result.user.LastName,
                    PhoneNumber = result.user.PhoneNumber,
                    Username = result.user.UserName,
                    UserRoles = result.UserRole.ToList(),//I guess you don't need this
                    Roles = result.Role.ToList(), 
                    PasswordHash = result.PasswordHash
                })
                .FirstOrDefault();

希望这会有所帮助。