【问题标题】:Any way to use method in EF Select extension?有什么方法可以在 EF Select 扩展中使用方法?
【发布时间】:2020-03-29 21:37:59
【问题描述】:

我有一个返回 ViewModel 异步的方法:

    public async Task<CardUserBindingViewModel> GetCardUserBindingViewModel(int cardId)
    {
            /// ... creditStatus, remainCreditDays
            return await Task.Run(() => new CardUserBindingViewModel
            {
                Id = card.Id,
                SerialNumber = card.SerialNumber,
                PurchaseDate = card.PurchaseDate,
                Cost = card.Cost,
                CreditStatus = creditStatus,
                RemainCreditDays = remainCreditDays.ToString(),
                Profile = null
            });
    }

并想将其用作 Select 表达式,例如:

    public async Task<IEnumerable<CardUserBindingViewModel>> FindByUserId(int userId)
    {
        return await Task.Run(() => 
            { 
                return _context.Card
                .Where(c => c.UserAccountId.Equals(userId))
                .AsEnumerable()
                .Select(async c => await GetCardUserBindingViewModel(c.Id));
            });
    }

错误是:

    Cannot implicitly convert type 
'System.Collections.Generic.IEnumerable<System.Threading.Tasks.Task<API.Models.CardUserBindingViewModel>>' to 
'System.Collections.Generic.IEnumerable<API.Models.CardUserBindingViewModel>'. An explicit conversion exists (are you missing a cast?)

是否可以防止在 Select 扩展中再次创建 ViewModel?

【问题讨论】:

  • 所有Task.Run 是怎么回事?在这两种方法中,但特别是在第一种方法中……创建新视图模型时您没有做任何工作,为什么将其包装在任务中?在第二种方法中也是值得怀疑的,EF Core 有异步操作符(即ToListAsync),你应该使用它来代替/结合
  • 如果我使用它就可以了:.Select(async c =&gt; await GetCardUserBindingViewModel(c.Id)).Select(x =&gt; x.Result); 让我知道它是否适合你,我可以像回答一样添加它。
  • @Sajid 无效,出现一个或多个错误时引发新错误。 (已经有一个打开的 DataReader 与此命令关联,必须先关闭。)
  • @pinkfloydx33 谢谢,但这两种方法有更多参考
  • 我认为您可以使用Task.WhenAll 并将查询分隔为两个子查询,如以下代码:var cards = context.Card.Where(c =&gt;c.UserAccountId.Equals(userId)).AsEnumerable();return await Task.WhenAll(cards.Select(c =&gt; GetCardUserBindingViewModel(c.Id)))

标签: c# linq entity-framework-core


【解决方案1】:

非常感谢@Sajid 和@pinkfloydx33,问题已经解决如下。

从以下方法中删除了 Task.Run():

public async Task<CardUserBindingViewModel> GetCardUserBindingViewModel(Card card)
{
    var creditRepository = _service.GetRequiredService<ICreditRepository>();

    var remainCreditDays = await creditRepository.GetCreditRemainDaysByCardId(card);

    var creditStatus = remainCreditDays > 0 ?
        "HasActiveCredit" : "Expired";

    return new CardUserBindingViewModel
    {
        Id = card.Id,
        SerialNumber = card.SerialNumber,
        PurchaseDate = card.PurchaseDate,
        Cost = card.Cost,
        CreditStatus = creditStatus,
        RemainCreditDays = remainCreditDays.ToString(),
        Profile = null
    };
}

修改 FindByUserId() 方法如下:

public async Task<IEnumerable<CardUserBindingViewModel>> FindByUserId(int userId)
{
    return _context.Card
            .Where(c => c.UserAccountId.Equals(userId))
            .AsEnumerable()
            .Select(async c => await GetCardUserBindingViewModel(c))
            .Select(c => c.Result);
}

最后将 MultipleActiveResultSets=true 添加到此处How to enable MultipleActiveResultSets 找到的 DBContext 连接字符串。

【讨论】:

    猜你喜欢
    • 2015-03-12
    • 1970-01-01
    • 2010-10-28
    • 2014-08-12
    • 2012-08-29
    • 2020-08-09
    • 2011-03-11
    • 2011-07-04
    • 1970-01-01
    相关资源
    最近更新 更多