【问题标题】:How to await during Select in a lambda如何在 lambda 中选择期间等待
【发布时间】:2016-10-24 17:47:15
【问题描述】:

我正在尝试使用 Entity Framework 从表执行 Lambda Select 到新模型,但我需要能够调用异步方法来填充返回集中每个实例的属性:

await Task.WhenAll(_context.UserContacts.Where(uc => uc.UserId == user.Id).Select(async uc => new MailContact
            {
                Email = uc.Contact.Email,
                UserId = uc.Contact.UserId,
                ContactId = uc.Contact.Id,
                Name = uc.Contact.UserId != null ? await _graphService.GetUserByIdAsync(uc.Contact.UserId) : null;
            }

我了解 Linq 对 await/async 的支持有限,并且我查看了 StackOverflow 上的其他几个示例,其中异步部分被移动到单独的循环中,例如:

How to await a method in a Linq query

T[] data = await Task.WhenAll(contacts.Select(c => LoadDataAsync(c)));

但是,除非我通过引用传递,否则此方法不会让我更新称为“c”的对象,这在异步方法中是不允许的。

有人可以解释正确填充 name 属性的最有效方法吗?

【问题讨论】:

    标签: c# lambda async-await


    【解决方案1】:

    您只需在 LINQ-to-Objects 中进行二次查找,而不是 LINQ-to-Entities:

    // LINQ-to-Entities
    var users = await _context.UserContacts
        .Where(uc => uc.UserId == user.Id)
        .Select(uc => new
        {
          uc.Contact.Email,
          uc.Contact.UserId,
          ContactId = uc.Contact.Id,
        })
        .ToListAsync();
    
    // LINQ-to-Objects
    var lookupTasks = users.Select(async u => new
        {
          u.Email,
          u.UserId,
          u.ContactId,
          Name = u.UserId != null ? await _graphService.GetUserByIdAsync(u.UserId) : null;
        });
    return await Task.WhenAll(lookupTasks);
    

    这个想法是您将尽可能多的逻辑推送到初始 LINQ-to-Entities 查询中,包括过滤和投影。然后你执行它(ToListAsync)。

    然后您获取数据库结果并进行二次查找。

    【讨论】:

    • 我想你可能打算使用return await Task.WhenAll(lookupTasks); 而不是return await Task.WhenAll(tasks);
    • 好的,知道了。我也没有想到将所有属性重新选择到一个新的动态属性中:)
    • 如果我只想返回从 GetUserByIdAsync 返回的对象的属性,我该如何访问它(.Result.DisplayName)?我收到警告没有 GetAwaiter 定义?
    • @SteveWhitaker:你可能不得不在await 周围加上括号,比如(await GetUserByIdAsync(id)).DisplayName
    【解决方案2】:

    我通过创建包装器解决了这个问题:

        private async Task<string> GetDisplayName(string userId)
        {
            if (string.IsNullOrEmpty(userId)) return null;
            var contactUser = await _graphService.GetUserByIdAsync(userId);
            return contactUser.DisplayName;
        }
    

    并将分配更改为:

        Name = u.UserId != null ? await GetDisplayName(u.UserId) : null
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-05-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-13
      • 2015-10-16
      相关资源
      最近更新 更多