我正在使用EF Core来处理预先存在的数据库。这是一个非常常见的模型,它使用很多联接表,具体针对我的情况,是users
至roles
的联接表。 UserRole
表只有两列-UserId
和RoleId
。
以下代码显示了我最近一次尝试将所有数据收集到一个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; }
}
答案 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();
希望这会有所帮助。