我有一个Readings的实体集合。
每个Reading都链接到一个名为Meter的实体。
(并且每个Meter拥有多个读数)。
每个Reading都有一个用于计量表ID(int)的字段和一个用于时间的字段。

下面是一些简化的代码来演示它:

public class Reading
{
    int Id;
    int meterId;
    DateTime time;
}

public class Meter
{
    int id;
    ICollection<Readings> readings;
}

给定特定的时间段和meterid列表,
什么是最有效的方式来获取每个仪表
在那个时间段的第一读和最后读?

我可以遍历所有仪表,并且每米都可以进行迭代
该期间的第一读和最后读,
但是我在徘徊,是否有一种更有效的方法来实现这一目标。

还有一个红利问题:同一个问题,但是要花费很多时间才能获取数据,
而不只是一个时期。

最佳答案

我不确定要如何获取这些数据,但可以将其投影为匿名类型:

var metersFirstAndLastReading = meters.Select(m => new
    {
        Meter = m,
        FirstReading = m.readings.OrderBy(r => r.time).First(),
        LastReading = m.readings.OrderBy(r => r.time).Last()
    });

然后,您可以像这样读取结果列表(此示例仅作为示例):
foreach(var currentReading in metersFirstAndLastReading)
{
    string printReadings = String.Format("Meter id {0}, First = {1}, Last = {2}",
                               currentReading.Meter.id.ToString(),
                               currentReading.FirstReading.time.ToString(),
                               currentReading.LastReading.time.ToString());

    // Do something...
}

另一个选择是在Meter中创建属性,该属性动态返回第一个和最后一个读数:
public class Meter
{
    public int id;
    public List<Reading> readings;

    public Reading FirstReading
    {
        get
        {
            return readings.OrderBy(r => r.time).First();
        }
    }

    public Reading LastReading
    {
        get
        {
            return readings.OrderBy(r => r.time).Last();
        }
    }
}

编辑:我对这个问题有点误解了。

这是确定仪表(包括)的日期范围的首末读数的实现(假设meterIdList是ID的ICollection<int>begin,而end是指定的日期范围)
var metersFirstAndLastReading = meters
    .Where(m => meterIdList.Contains(m.id))
    .Select(m => new
    {
        Meter = m,
        FirstReading = m.readings
                        .Where(r => r.time >= begin && r.time <= end)
                        .OrderBy(r => r.time)
                        .FirstOrDefault(),
        LastReading = m.readings
                        .Where(r => r.time >= begin && r.time <= end)
                        .OrderByDescending(r => r.time)
                        .FirstOrDefault()
    });

您现在将无法使用属性(因为您需要提供参数),因此方法可以很好地替代:
public class Meter
{
    public int id;
    public List<Reading> readings;

    public Reading GetFirstReading(DateTime begin, DateTime end)
    {
        var filteredReadings = readings.Where(r => r.time >= begin && r.time <= end);

        if(!HasReadings(begin, end))
        {
            throw new ArgumentOutOfRangeException("No readings available during this period");
        }

        return filteredReadings.OrderBy(r => r.time).First();
    }

    public Reading GetLastReading(DateTime begin, DateTime end)
    {
        var filteredReadings = readings.Where(r => r.time >= begin && r.time <= end);

        if(!HasReadings(begin, end))
        {
            throw new ArgumentOutOfRangeException("No readings available during this period");
        }

        return filteredReadings.OrderBy(r => r.time).Last();
    }

    public bool HasReadings(DateTime begin, DateTime end)
    {
        return readings.Any(r => r.time >= begin && r.time <= end);
    }
}

10-08 01:35