如何将多个LINQ对对象的请求合并为一个

本文关键字:合并 一个 请求 对象 LINQ | 更新日期: 2023-09-27 18:06:54

我想将GetCurrentAuction重写为单个LINQ请求:

private AuctionInfo GetCurrentAuction()
    {
        var auctions = Auctions.List().ToList();
        var liveAuction = auctions
            .Where(AuctionIsLive)
            .OrderBy(a => a.StartDate)
            .FirstOrDefault();
        if (liveAuction != null)
        {
            return liveAuction;
        }
        var openAuction = auctions
            .Where(AuctionIsOpen)
            .OrderBy(a => a.StartDate)
            .FirstOrDefault();
        if (openAuction != null)
        {
            return openAuction;
        }
        // next upcoming auction
        return auctions
            .Where(a => a.StartDate >= DateTime.UtcNow)
            .OrderBy(a => a.StartDate)
            .FirstOrDefault();
    }
    private bool AuctionIsLive(AuctionInfo auction)
    {
        // WorkflowStage is int
        return auction.WorkflowStage == LIVE_WORKFLOW_STAGE;
    }
    private bool AuctionIsOpen(AuctionInfo auction)
    {
        return auction.WorkflowStage == OPEN_WORKFLOW_STAGE;
    }

有人能建议如何实现这一点吗?看起来使用auctions.GroupBy(a => a.WorkflowStage)并没有让我更接近解决方案。

如何将多个LINQ对对象的请求合并为一个

您可以通过对它们进行排序来指示偏好-例如:

return
  Auctions.List().ToList()  //--> ToList() not needed here?
  .Where
  ( a =>
    AuctionIsLive(a) ||
    AuctionIsOpen(a) ||
    a.StartDate >= DateTime.UtcNow
  )
  .OrderBy
  ( a => 
    AuctionIsLive( a ) ? 0 :
    AuctionIsOpen( a ) ? 1 : 2
  )
  .ThenBy( a => a.StartDate )
  .FirstOrDefaut();

你可以使用非常有用的?? ?(https://msdn.microsoft.com/en-us/library/ms173224.aspx)操作符并实现:

        var result = auctions.Where(AuctionIsLive).OrderBy( x => x.StartDate).FirstOrDefault() ?? 
            auctions.Where(AuctionIsOpen).OrderBy( x => x.StartDate).FirstOrDefault() ??
            auctions.Where(a => a.StartDate >= DateTime.UtcNow).OrderBy(a => a.StartDate).FirstOrDefault();
        return result;

这取决于你正在使用的数据源和LINQ提供程序。例如,如果您使用LINQ to SQL,则首选的方法是使用Expressions来节省内存,并最终得到类似于@fankyCatz的答案:

return Auctions.Where(a => a.WorkflowStage == LIVE_WORKFLOW_STAGE).OrderBy(x => x.StartDate).FirstOrDefault() ??
        Auctions.Where(a => a.WorkflowStage == OPEN_WORKFLOW_STAGE).OrderBy(x => x.StartDate).FirstOrDefault() ??
        Auctions.Where(a => a.StartDate >= DateTime.UtcNow).OrderBy(a => a.StartDate).FirstOrDefault();

然而,只使用LINQ to Objects,我最终会得到类似于@Clay的答案,只是会提高映射的可读性:

public static Dictionary<int, Func<AuctionInfo, bool>> Presedence = 
            new Dictionary<int, Func<AuctionInfo, bool>>
{
    { 0, a => a.WorkflowStage == LIVE_WORKFLOW_STAGE },
    { 1, a => a.WorkflowStage == OPEN_WORKFLOW_STAGE },
    { 2, a => a.StartDate >= DateTime.UtcNow },
};
//in your GetCurrentAuction()
return Auctions.Where(a => Presedence.Any(p => p.Value(a)))
                .OrderBy(a => Presedence.First(p => p.Value(a)).Key)
                .ThenBy(a => a.StartDate)
                .FirstOrDefault();