Использовать Select в async

229
16 ноября 2021, 17:40

если не сложно тыкните меня в ошибку, не могу понять как использовать селект в асинхронном методе... Код интерфейса:

public interface IUserService
    {       
        Task<List<User>> GetIdentity();
    }

сервис:

public class UserService : IUserService
    {
        DBUserContext db;
        public UserService(DBUserContext context)
        {
            db = context;
        }       
        public async Task<List<User>> GetIdentity()
        {
            return await db.Users.Include(x => x.UserFriends).ThenInclude(x => x.User).ToListAsync();
        }       
    }

и сам контроллер:

[HttpGet, Route("getidenti"), Authorize(Roles = "Manager")]
        public async Task<IActionResult> Get()
        {           
            UserViewModel userdb = userService.GetIdentity().Select( c =>  new UserViewModel        
            {
                Id = c.Id,
                UserName = c.UserName,
                Password = c.Password,
                LastName = c.LastName,
                Friends = c.UserFriends.Select(x => new UserFriendsViewModel(x)).ToList()
            }).ToList();
        return Ok(userdb);
        }

ругается на селект, мол не может он работать с асинхронным методом, если делаю все части без асинка, но все получается отлично и все работает, но как я понимаю, желательно чтоб все было асинковым, и так не могу уже 3-й час ничего найти...

Answer 1

Дождитесь таска и выполните Select:

public async Task<IActionResult> Get()
{   
    var users = await userService.GetIdentity();
    var usersVm = users
        .Select(c =>  new UserViewModel        
        {
            Id = c.Id,
            UserName = c.UserName,
            Password = c.Password,
            LastName = c.LastName,
            Friends = c.UserFriends.Select(x => new UserFriendsViewModel(x)).ToList()
        })
        .ToList();
    return Ok(usersVm);
}
Answer 2

Вы не дожидаетесь выполнения GetIdentity, ибо он возвращает Task>, а не List

Надо переписать вот так

UserViewModel userdb = (await userService.GetIdentity()).Select(c => 

В целом я не знаю контекста, но вам не нужно в GetIdentity делать ToListAsync. Ибо получается вы лишние действия делаете в памяти( в данном случае мало что изменится вроде, но так делать не стоит). Обычно делается так:

public IQueryable<User> GetIdentity()
    {
        return db.Users.Include(x => x.UserFriends).ThenInclude(x => x.User);
    }     
// И теперь можете писать
UserViewModel userdb = await userService.GetIdentity().Select( c =>  new UserViewModel        
        {
            Id = c.Id,
            UserName = c.UserName,
            Password = c.Password,
            LastName = c.LastName,
            Friends = c.UserFriends.Select(x => new UserFriendsViewModel(x)).ToList()
        }).ToListAsync();

Тобишь раньше GetIdentity лез в базу, доставал все в память, а потом вы делаете что хотите(и все последующие действия будут в памяти, хотя часть из них должна быть в запросе. Например если вы захотите сделать OrderBy после GetIdentity, то это будет выполнено в памяти, а не в запросе к бд, что намного дольше, особенно если данных дофига).

А теперь GetIdentity просто обернул в себя начальное построение запроса. На этом этапе он еще не идет в базу, пока вы явно не обратитесь к переменной или не вызовите что-то типа ToList(), Result, ToListAsync(пока вы явно не обратитесь к данным)

READ ALSO
Перегрузка оператора при наследовании

Перегрузка оператора при наследовании

Можно как-нибудь наследовать перегрузку операторов? Сейчас я повторно дублирую код, например как в нижеприведенном коде

213
Как подключить кодировку UTF-8 в mysql?

Как подключить кодировку UTF-8 в mysql?

У меня есть опрос на сайте, оно с помощью sqlquery = select берет вопросы с базы данных, и показывает на сайте, но сейчас вместо букв стоит символ ?, как...

158
Не могу получить ссылку на скачку видео(Youtube)

Не могу получить ссылку на скачку видео(Youtube)

Не могу получить ссылку на скачку некоторых видео с ютуба https://wwwyoutube

84