SQL语句的某些部分嵌套得太深

时间:2012-11-18 16:31:46

标签: entity-framework linq-to-entities

我有以下代码

[WebGet]
        public Bid GetHighestBidInOpenAuctions(int auctionEventId)
        {
            var auctionEvent = CurrentDataSource.AuctionEvents.Where(x => x.Id == auctionEventId).FirstOrDefault();
            var auctionIds = CurrentDataSource.Auctions.Where(x => x.AuctionEventId == auctionEventId && x.Ends > DateTime.UtcNow).Select(x => x.Id).ToList();

            var bids = CurrentDataSource.Bids.Where(x => auctionIds.Any(t => t == x.AuctionId));

            // If the auction Event has not yet started or there are no bids then show auction with high pre-sale estimate.
            if (bids.Count() == 0 || auctionEvent.Starts > DateTime.UtcNow)
            {
                return null;
            }

            var highestBid = bids.Where(b => b.IsAutobid == false).OrderByDescending(b => b.Amount).FirstOrDefault();

            return highestBid;
        }

此行抛出以下异常

if (bids.Count() == 0 || auctionEvent.Starts > DateTime.UtcNow)

Some part of your SQL statement is nested too deeply. Rewrite the query or break it up into smaller queries.

怎么了?

修改

我试过这样做

IQueryable<Bid> bids = CurrentDataSource.Bids.Where(b => 0 == 1);
            foreach(var auctionId in auctionIds)
            {
                int id = auctionId;
                bids = bids.Union(CurrentDataSource.Bids.Where(b => b.AuctionId == id));
            }

但我仍然得到同样的错误。

3 个答案:

答案 0 :(得分:1)

请尝试将出价查询替换为:

,而不是使用子查询
var bids = CurrentDataSource.Bids.Where(b => b.AuctionEventId == auctionEventId
                && b.Auction.AuctionEvent.Starts > DateTime.UtcNow
                && b.Auction.Ends > DateTime.UtcNow);

if (bids.Count() == 0
{
    return null;
}

答案 1 :(得分:0)

看来当你的数据库中有太多东西时你就会得到这个错误(在我的情况下是auctionIds),因为生成的sql会嵌套太深。为了解决这个问题,我提出了这个解决方案。如果有人能做得更好那么就做。我发布这个是因为将来可能会有这个错误,如果有的话,如果没有更好的解决方案,这可能有助于他们。

 [WebGet]
        public Bid GetHighestBidInOpenAuctions(int auctionEventId)
        {
            /* 
             * This method contains a hack that was put in under tight time constraints.  The query to
             * get bids for all open auctions used to fail when we had a large number of open auctions.
             * In this implementation we have fixed this by splitting the open auctions into groups of 20
             * and running the query on those 20 auctions and then combining the results.
            */

            const int auctionIdSegmentSize = 20;
            var auctionEvent = CurrentDataSource.AuctionEvents.Where(x => x.Id == auctionEventId).FirstOrDefault();
            var auctionIds = CurrentDataSource.Auctions.Where(x => x.AuctionEventId == auctionEventId && x.Ends > DateTime.UtcNow).Select(x => x.Id).ToList();

            int numberOfSegments = auctionIds.Count/auctionIdSegmentSize;
            if (auctionIds.Count % auctionIdSegmentSize != 0)
                numberOfSegments++;

            var bidsList = new List<IQueryable<Bid>>();
            for (int i = 0; i < numberOfSegments; i++)
            {
                int start = i*auctionIdSegmentSize;
                int end;
                if (i == numberOfSegments - 1)
                {
                    end = auctionIds.Count - 1;
                }
                else
                {
                    end = ((i + 1)*auctionIdSegmentSize) - 1;
                }

                var subList = auctionIds.GetRange(start, (end - start) + 1);
                bidsList.Add(CurrentDataSource.Bids.Where(b => subList.Any(id => id == b.AuctionId)));
            }

            // If the auction Event has not yet started or there are no bids then show auction with high pre-sale estimate.
            if (IsBidsCountZero(bidsList) || auctionEvent.Starts > DateTime.UtcNow)
            {
                return null;
            }

            var highestBid = FindHighestBid(bidsList);

            return highestBid;
        }

        private Bid FindHighestBid(List<IQueryable<Bid>> bidsList)
        {
            var bids = new List<Bid>();
            foreach (var list in bidsList)
            {
                bids.Add(list.Where(b => b.IsAutobid == false).OrderByDescending(b => b.Amount).FirstOrDefault());
            }

            bids.RemoveAll(b => b == null);

            if (bids.Count == 0)
                return null;

            bids.Sort(BidComparison);

            return bids[0];
        }

        private int BidComparison(Bid bid1, Bid bid2)
        {
            if (bid1.Amount < bid2.Amount)
                return 1;
            if (bid1.Amount > bid2.Amount)
                return -1;
            return 0;
        }

        private bool IsBidsCountZero(List<IQueryable<Bid>> bidsList)
        {
            int count = 0;
            foreach (var list in bidsList)
            {
                count += list.Count();
            }

            return count == 0;
        }

答案 2 :(得分:0)

问题在于auctionIds.Any(t => t == x.AuctionId),其中EF无法创建正确的查询。您可以将其更改为:

var bids = CurrentDataSource.Bids.Where(x => auctionIds.Contains(x.AuctionId));

EF可以将auctionIds转换为集合并传递给DB。