如何使用多个包含因子分解Linq请求?

时间:2017-02-08 10:34:53

标签: c# entity-framework linq entity-framework-6

我的模特有:

  • 多个DeviceStatus附加到一个强制性Device
  • 多个Device附加到一个强制性Panel

当我查询DeviceStatus时,我需要在查询结果中附加DevicePanel

... DeviceStatus.Device在查询结果中为空。

这是Linq查询:

using (var actiContext = new ActigraphyContext())
{
    var todayStatus =
        from s in actiContext.DeviceStatus.Include(s1 => s1.Device.Panel)
        where DbFunctions.TruncateTime(s.TimeStamp) == DbFunctions.TruncateTime( DateTimeOffset.Now)
                && s.Device.Panel.Mac == mac
                && (s.Device.Ty == 4 || s.Device.Ty == 9)
        select s;

    // var tempList = todayStatus.toList();

    var todayLastStatus =
        from s in todayStatus.Include(s1 => s1.Device.Panel)
        let lastTimeStamp = todayStatus.Max(s1 => s1.TimeStamp)
        where s.TimeStamp == lastTimeStamp
        select s;

    var requestResult =  todayLastStatus.FirstOrDefault();

    return requestResult;
}

如果我取消注释未使用tempList的行// var tempList = todayStatus.toList();,它可以正常工作:requestResult.Device已设置! 但不好的一面是今天,Status.toList会触发一个带来大量数据的请求。

那么如何使用相关对象获取DeviceStatus?

注意:后面的数据库是SQL Server 2012

3 个答案:

答案 0 :(得分:2)

当您通过LINQ查询调用Include()时,它会执行Eagerly Loading。

如MSDN中所述: 预先加载是一种过程,其中对一种类型的实体的查询也将相关实体作为查询的一部分加载。通过使用Include方法实现预先加载。 读取实体时,将同时检索相关数据。这通常会导致单个连接查询检索所需的所有数据。您可以使用Include方法指定预先加载。

所以你需要调用.toList()来完成查询执行。

由于数据量很大,您可以使用Select子句根据您的要求提取相对特定的列。

var todayStatus =
    from s in actiContext.DeviceStatus
    .Include(s1 => s1.Device.Panel.Select(d => new 
                                            {
                                              d.DeviceId,
                                              d.DeviceName,
                                              d.PanelID
                                            }))
    where DbFunctions.TruncateTime(s.TimeStamp) == DbFunctions.TruncateTime( DateTimeOffset.Now)
            && s.Device.Panel.Mac == mac
            && (s.Device.Ty == 4 || s.Device.Ty == 9)
    select s;

var tempList = todayStatus.toList();

答案 1 :(得分:0)

好的,这个请求是一种更简单的方法来实现这个目标:

        using (var actiContext = new ActigraphyContext())
        {
            var todayLastStatus =
                from s in actiContext.DeviceStatus.Include(s1 => s1.Device.Panel)
                where DbFunctions.TruncateTime(s.TimeStamp) == DbFunctions.TruncateTime( DateTimeOffset.Now)
                      && s.Device.Panel.Mac == mac
                      && (s.Device.Ty == 4 || s.Device.Ty == 9)
                orderby s.TimeStamp descending 
                select s;

            var requestResult = todayLastStatus.Take(1).FirstOrDefault();

            return requestResult;
        }

但问题仍然存在:为什么我在第一次请求中没有获得相关对象?

答案 2 :(得分:-1)

在您执行类似ToList()的调用之前,查询实际上并未运行,这就是取消注释该行的原因。如果查询带回了太多数据,那么您需要更改查询以缩小您带回的数据量。