【问题标题】:Order dynamic list of object by common property with pagination按具有分页的公共属性对对象的动态列表进行排序
【发布时间】:2020-05-12 16:34:11
【问题描述】:

我有几种类型的对象,它们是从数据库中获取的,具有不同的模型,它们具有共同的 date 属性。我想对所有这些模型进行排序,但最后只按页面提取数据。问题是当我在动态列表中添加所有 IQuerable 模型时,它们会从数据库中提取所有数据,如果有数百条记录的话需要很长时间。

我已经做了什么:

  1. 创建了基础接口并在从他那里继承的模型中。
  2. 在动态列表中添加了所有模型。
  3. 按公共属性排序此列表。
  4. 添加了带有 X.PagedList 的页面

示例代码:

型号:

        private interface BaseInfo
        {
            public DateTime Date { get; set; }
        }

        public class CompanyEvent : BaseInfo
        {
            public string Description { get; set; }
            public DateTime Date { get; set; }
        }
        public class SummerEvent : BaseInfo
        {
            public bool IsActive { get; set; }
            public DateTime Date { get; set; }
            public string MainPartner { get; set; }
        }
        public class Birthday : BaseInfo
        {
            public string FirstName { get; set; }
            public string LastName { get; set; }
            public int Age { get; set; }
            public DateTime Date { get; set; }

        }

代码

 public IPagedList<dynamic> GetDynamicInfo(int pageNumber)
        {
            int pageSize = 10;
            List<dynamic> dynamicList = new List<dynamic>();

            IQueryable<CompanyEvent> companyEvents = Employees.Select(a => new CompanyEvent()
            {
                Date = a.EventDate,
                Description = a.Description
            });
            IQueryable<SummerEvent> summerEvents = Employees.Select(a => new SummerEvent()
            {
                Date = a.StartEventDate,
                IsActive = a.IsActive,
                MainPartner = a.Partner.Name
            });
            IQueryable<Birthday> birthdays = Employees.Select(a => new Birthday()
            {
                Date = a.DateBorn,
                FirstName = a.FirstName,
                a.LastName = a.LastName
            });
            dynamicList.AddRange(companyEvents);
            dynamicList.AddRange(summerEvents);
            dynamicList.AddRange(birthdays);
            var sortedDynamicList = dynamicList.OrderBy(a => ((BaseInfo)a).Date).ToPagedList(pageNumber, pageSize);
            return sortedDynamicList;
        }

【问题讨论】:

  • 一个常见的初学者错误是检索很多,然后在程序中进行过滤。不要那样做。在 DB Query 本身期间进行尽可能多的过滤、处理,尤其是分页。您的 C# 代码永远无法超越数据库的性能,而且充其量只会增加大量浪费的网络时间。 |我不太确定如何使用 linq-to-entities 来做到这一点(或者它是否可以工作)。但是根据 DBMS,您可以添加一个视图,将所有这些值计算出来并组合起来。
  • @Christopher 他正在使用IQueryable 这将使过滤分页发生在数据库中

标签: c# linq linq-to-entities


【解决方案1】:

当您使用ToPageList 时,它将所有数据都带入内存。您可以使用 SkipTake ,它们将被翻译成各自的 sql 并在 DB 端进行分页,例如:

var sortedDynamicList = dynamicList
                      .OrderBy(a => ((BaseInfo)a).Date)
                      .Skip(pageNumber)
                      .Take(pageSize)
                      .ToPagedList(pageNumber, pageSize);

其次,您可以使用IPagedList&lt;BaseInfo&gt;,而不是使用IPagedList&lt;dynamic&gt;,这也是同样的工作方式。

更新:

由于在这种情况下,数据是从不同的表甚至其中的不同列加载的,一种可能的方法是分别加载它们的每一页,然后对这些数据进行排序和分页,例如:

IQueryable<CompanyEvent> companyEvents = Employees.Skip(pageNumber).Take(pageSize)
       .Select(a => new CompanyEvent()
        {
            Date = a.EventDate,
            Description = a.Description
        });

IQueryable<SummerEvent> summerEvents = Employees.Skip(pageNumber).Take(pageSize)
        .Select(a => new SummerEvent()
        {
            Date = a.StartEventDate,
            IsActive = a.IsActive,
            MainPartner = a.Partner.Name
        });

IQueryable<Birthday> birthdays = Employees.Skip(pageNumber).Take(pageSize)
        .Select(a => new Birthday()
        {
            Date = a.DateBorn,
            FirstName = a.FirstName,
            a.LastName = a.LastName
        });

然后执行以下操作:

        dynamicList.AddRange(companyEvents);
        dynamicList.AddRange(summerEvents);
        dynamicList.AddRange(birthdays);
        var sortedDynamicList = dynamicList.OrderBy(a => ((BaseInfo)a).Date)
                                           .ToPagedList(pageNumber, pageSize);

【讨论】:

  • 当我将数据添加到动态列表时:dynamicList.AddRange(companyEvents);动态列表.AddRange(summerEvents); dynamicList.AddRange(生日);所有数据都已经进入内存,我想避免这种情况......
  • @Librain 是的,这会将它们带入内存,你不能那样做,你需要从三个表中分别查询分页数据,然后在内存中对它们进行排序并选择所需的数据,或者你将需要编写 sql 查询或存储过程,因为您的场景与正常情况完全不同
  • @Librain 我已经用一种可能的方法更新了答案
  • 感谢您的回复,但会有几个问题。如果我从表中取出某些部分,则无法保证此数据会在结果中,因为我按日期排序,也无法获取所有页数...
  • @Librain 你需要重新考虑你的方法,它目前已经变得复杂
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多