从 IQueryable 创建自定义对象,无需将所有内容加载到内存中

Create custom objects from IQueryable without loading everything into memory

这是 的后续问题。你应该先读一下。

感谢 ,我现在创建了一个查询,该查询将 return 正确的条目。参见:

IQueryable<Data> onePerHour = dataLastWeek
    .Where(d => 
        !dataLastWeek
        .Any(d2 =>
            d2.ArchiveTime.Date == d.ArchiveTime.Date &&
            d2.ArchiveTime.Hour == d.ArchiveTime.Hour &&
            d2.ArchiveTime < d.ArchiveTime));

现在为了处理条目并将它们显示在图表上,我只需要模型的一个或两个属性 class Data。用例是这样的:

List<Data> actualData = onePerHour.ToList();

var tempCTupels = new List<TimeTupel<float>>();
tempCTupels.AddRange(actualData.Select(d => new TimeTupel<float>(d.ArchiveTime, d.TempC)));

var co2Tupels = new List<TimeTupel<float>>();
tempCTupels.AddRange(actualData.Select(d => new TimeTupel<float>(d.ArchiveTime, d.CO2Percent)));

TimeTupel很简单,定义如下:

public class TimeTupel<TData>
{
    public TimeTupel(DateTime time, TData yValue)
    {
        Time = time;
        YValue = yValue;
    }

    public DateTime Time { get; set; }
    public TData YValue { get; set; }
}

问题

当前 actualdata 是一个 List<Data> 这意味着它已完全加载到内存中。
因为我只使用两个属性,所以我不需要检索整个对象来创建 TimeTupels。

现在我的问题是如何实现性能提升?删除 ToList 是正确的方法吗?

我尝试过的事情

您可以在 Select 语句中使用匿名类型来仅将需要的数据列检索到内存中,然后将该 in-memory 数据转换为 TimeTupel<> class从那里。它看起来像这样:

var actualData = dataLastWeek
    .Where(d => 
        !dataLastWeek
        .Any(d2 =>
            d2.ArchiveTime.Date == d.ArchiveTime.Date &&
            d2.ArchiveTime.Hour == d.ArchiveTime.Hour &&
            d2.ArchiveTime < d.ArchiveTime))
    .Select(d => new { d.ArchiveTime, d.TempC, d.CO2Percent})
    .ToList();

var tempCTupels = actualData.Select(d => new TimeTupel<float>(d.ArchiveTime, d.TempC)).ToList();

var co2Tupels = actualData.Select(d => new TimeTupel<float>(d.ArchiveTime, d.CO2Percent)).ToList();

在实际从 IQueryable 加载对象之前,您可以 select 只有您需要的属性。在 Where 语句之后使用 Select 以仅加载您需要的内容。

一个例子:

假设您有一个 class 如下所示:

public class Person {
        public string Name { get; set; }
        public int Age { get; set; }
    }

我可以初始化一个测试项目列表:

var people = new List<Person> { new Person { Name = "John", Age = 10 }, new Person { Name = "Archie", Age = 40 } };

然后我们应用过滤器:

var filterred = people.Where(p => p.Age > 15).Select(p => p.Name).ToList();

如果我想用 selection 创建一个新对象,select 多于一个 属性,我可以这样做:

var objFilterred = people.Where(p => p.Age > 15).Select(p => new { FullName = p.Name  }).ToList();

您不必使用匿名对象,您也可以创建一个新的 class 只包含您需要的属性并简单地填充它。

您不能 "remove" ToList,因为这是实际执行查询的内容。 IQueryable 不是数据,它是一个尚未 运行 的查询,您可以根据需要链接任意数量的内容。最后一步是执行它,运行ning 类似 ToList 的东西,以实际加载对象。只要您构建 IQueryable 并在完成后执行它,那么您应该会看到执行速度的提高