LINQ .Take()返回的元素多于请求的元素

时间:2012-08-16 08:22:32

标签: c# linq entities

我们有一个简单的LINQ-to-Entities查询,它应该从特定页面返回特定数量的元素。 请求的示例可以是:

var query = from r in records
            orderby r.createdDate descending
            select new MyObject()
            { ... };

//Parameters: pageId = 8, countPerPage = 10
List<MyObject> list = query.Skip(pageId * countPerPage).Take(countPerPage);

以上示例在大多数情况下都很有效,但有时列表中包含的元素超过10个。这似乎并不总是正确的,取决于数据库数据。 例如,当我们请求页面10并将countPerPage作为10时,我们得到10个元素。但是当我们请求页面12并将countPerPage传递为10时,我们得到了11个元素。然后,当我们要求第21页时,我们再次获得10个元素。

有没有可能出现这种情况的原因?

更新: 当然,查询并不像在示例中那么简单,并且包含子查询。

这是一个更完整的例子:

var elementsQuery = from m in entityContext.elements
                    where m.elementSearchText.Contains(filter)
                    orderby m.CreatedDate descending
                    select new DataContracts.ElementForWeb()
                    {
                        FirstName = m.FirstName,
                        LastName = m.LastName,
                        Photos = (from p in m.Photos select p.ID),
                        PlacesCount = m.Childs.Where(x => x.Place != null).Count() + ((m.MainChild != null)?1:0),
                        SubElements = (
                            from t in m.Childs
                            orderby t.CreatedDate descending
                            select new DataContracts.ChildForWeb()
                            {
                                CommentsCount = t.ChildComments.Count,
                                Photos = (from p in t.Photos select p.ID),
                                Comments = (from c in t.ChildComments
                                orderby c.CreatedDate descending
                                select new DataContracts.CommentForWeb()
                                {
                                    CommentId = c.ID,
                                    CommentText = c.CommentText,
                                    CreatedByPhotoId = c.Account.UserPhoto,
                                    CreatedDate = c.CreatedDate,
                                }).Take(5)
                            }).Take(5)
                      };

List<DataContracts.ElementForWeb> elements = 
    new List<DataContracts.ElementForWeb>(
        elementsQuery
           .Skip(pageId * countPerPage)
           .Take(countPerPage));

UPDATE2 :这是更有趣的测试。

        for (var i = 0; i < 10; i++) {
            Service.GetElementsForWebPaged(12, 10, "",
                function (result) {
                    console.log("Elements returned: " + result.length);
                },
                function (error) {
                });
        }

结果是“棒极了”!

Elements returned: 11
Elements returned: 11
Elements returned: 10
Elements returned: 11
Elements returned: 11
Elements returned: 10
Elements returned: 11
Elements returned: 10
Elements returned: 11
Elements returned: 11

1 个答案:

答案 0 :(得分:1)

测试此答案很难,因为它取决于您的架构和测试数据等。 但我相信你可能在将IQueryAble结果与IEnumerable结果混淆时遇到了问题。

请记住,在foreach或ToList()完成之前,linq-To-Entities查询实际上不会对数据库进行往返。

我建议先把它分成几部分:

var elementsQuery = from m in entityContext.elements
                    where m.elementSearchText.Contains(filter)
                    orderby m.CreatedDate descending;

var elements = elementsQuery.Skip(pageId * countPerPage).Take(countPerPage)).ToList();

然后建立投影...

var elementsForWeb = from m in elements
                     select new DataContracts.ElementForWeb()
                     {
                     ...
                     }