Изменить код для повышения производительности (нетерпеливая загрузка) - PullRequest
0 голосов
/ 14 апреля 2019

У меня есть этот код для поиска UserInfo и поиска роли пользователя в UserRole и поиска информации о роли из Role.

Я использую таблицу идентификаторов.

этомой код:

public virtual async Task<ActionResult<List<User>>> GetuserList(CancellationToken cancellationToken)
{
    var userDto = new UserDto();
    var users = await userManager.Users.Include(x => x.UserRoles).ThenInclude(t=>t.Role).ToListAsync();

    return users;
}

Но этот код не подходит для производительности, потому что на первом шаге он получает всю информацию пользователя userManager.Users, на втором шаге находит всю информацию user role и снова находит всю информацию пользователя .Include(x => x.UserRoles)и найти всю информацию о роли .ThenInclude(t=>t.Role).

Мне просто нужно roleID от UserRole и roleName от Role.

Что я должен сделать, чтобы загрузить необходимую информацию не для всех из них?

Обновить код:

Я пишу этот код:

var users = userManager.Users.Select(x => new UserDto
        {
            UserName = x.UserName,
            Email = x.Email,
            Family = x.Family,
            Name = x.Name,
            Password = x.PasswordHash,
            PhoneNumber = x.PhoneNumber,
            RoleId = x.UserRoles.FirstOrDefault(t => t.UserId == x.Id).UserId
        });

но все же мне нужно найти RoleName на RoleTabel, но он не может использовать Include в Select.как я могу найти найти RoleName ????

Ответы [ 3 ]

1 голос
/ 14 апреля 2019

До тех пор, пока вы не вызовете ToListAsync(), который выполняет ваш запрос к источнику данных, вы можете формировать свой запрос с помощью функций Include, ThenInclude, Select, Where и т. Д.

Что вам нужно сделать, это просто объединить ваш первый квест с проекцией в вашем обновлении.

public virtual async Task<ActionResult<List<User>>> GetuserList(CancellationToken cancellationToken)
{
    var userDto = new UserDto();
    var users = await userManager.Users.Include(x => x.UserRoles).ThenInclude(t=>t.Role)
       .Select(x => new UserDto
        {
            UserName = x.UserName,
            Email = x.Email,
            Family = x.Family,
            Name = x.Name,
            Password = x.PasswordHash,
            PhoneNumber = x.PhoneNumber,
            RoleId = x.UserRoles.FirstOrDefault(t => t.UserId == x.Id).UserId
        })
      .ToListAsync();

    return users;
}
1 голос
/ 15 апреля 2019

Чтобы выбрать из ссылок на вложенные дочерние таблицы, я использую подход, заключающийся в том, чтобы выбрать анонимный тип для построения эффективного запроса, а затем сократить его до DTO.

Например:

var users = userManager.Users.Select(x => new 
{
    UserName = x.UserName,
    Email = x.Email,
    Family = x.Family,
    Name = x.Name,
    Password = x.PasswordHash,
    PhoneNumber = x.PhoneNumber,
    Role = x.UserRoles.Select(r => new { r.RoleId, r.Role.RoleName}).FirstOrDefault()
}).ToList()
.Select(x => new UserDto
{
    UserName = x.UserName,
    Email = x.Email,
    Family = x.Family,
    Name = x.Name,
    Password = x.PasswordHash,
    PhoneNumber = x.PhoneNumber,
    RoleId = x.Role?.RoleId,
    RoleName = x.Role?.RoleName
}).ToList();

Вы можете обойтись одним .Select, хотя это может привести к менее эффективному SQL, так как каждый внутренний .FirstOrDefault() и т. Д., Вероятно, повторно присоединит таблицы UserRole / Role. Таким образом, первый .Select() строит SQL для вложенной структуры, содержащей дочерние данные, которые нам нужны, затем второй работает с результирующими анонимными типами POCO, создавая плоский DTO для возврата.

И последнее: при использовании .First() / .FirstOrDefault() вы должны использовать предложение .OrderBy(), чтобы обеспечить предсказуемый результат, если вы хотите получить только одну запись из возможных многих.

Кроме того, учитывая, что мы используем .Select() для отображения нашего вывода, вам не нужно использовать .Include() для выбора из связанных объектов. Вам также не нужно выражение .Where() внутри ваших User.UserRoles. (User.UserRoles будет содержать только UserRoles для этого UserId). Здесь вы увидите, что .Where() предложения используются при соединении свободно связанных таблиц из DbContext. Непосредственно связанные отношения сущностей через сопоставленные FK предпочтительнее.

Редактировать: учитывая, что у каждого пользователя может не быть роли, во втором .Select() вам нужно будет использовать «?». оператор для получения идентификатора роли и имени. Это будет означать, что идентификатор роли DTO должен быть нулевым. Если вы хотите использовать RoleId по умолчанию 0 или около того, вместо этого вы можете использовать RoleId = x.Role?.RoleId ?? 0

0 голосов
/ 14 апреля 2019

У меня есть нечто похожее, что, надеюсь, поможет.Он прекрасно работает

      if (users != null && users.Length > 0 )
        {
            foreach (var item in users)
            {
                var userRoles = await UserManager.GetRolesAsync(item);
                if (userRoles.Contains("Foreman"))
                {
                    CW.AddRange(db.CrewMemberForeman.Where(x => x.AssignedForemanId == item).Select(x => x.CrewMember).OrderBy(x => x.FirstName).ToList());
                }
            }
        }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...