Some part of your SQL statement is nested too deeply

本秂侑毒 提交于 2019-12-23 04:43:56

问题


I have the following code

[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;
        }

This line throws the below exception

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.

What's wrong?

EDIT

I have tried doing this

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));
            }

But I still get the same error.


回答1:


Rather than using a subquery, try replacing the bid query with:

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;
}



回答2:


It seems when you have too many things in your database then you will get this error (auctionIds in my case) because the generated sql will be too deeply nested. To solve this I came up with this solution. If anyone can do better then do. I'm posting this because someone may have this error in the future and if they do, in the absence of a better solution this might help them.

 [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;
        }



回答3:


The problem is with auctionIds.Any(t => t == x.AuctionId) where EF cannot create a correct query. You can change it to:

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

Where EF can convert auctionIds to a collection and pass to DB.



来源:https://stackoverflow.com/questions/13442065/some-part-of-your-sql-statement-is-nested-too-deeply

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!