2012-03-19 19 views
6

Tengo datos que se graban cada 15 minutos en las tablas PowerStringHistorys y PowerCombinerHistorys. Soy nuevo en LINQ y estoy tratando de descubrir cómo crear una consulta que agrupe mis datos por hora y para esa hora el promedio actual. Aquí es lo que tengo hasta ahoraAgrupar por hora usando LINQ

 TimeZoneInfo easternZone = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time"); 
     DateTime UTC_StartingDate = TimeZoneInfo.ConvertTimeToUtc(StartingDate, easternZone); 
     DateTime UTC_EndingDate = TimeZoneInfo.ConvertTimeToUtc(EndingDate, easternZone); 

     var FirstQ = from p in db.PowerStringHistorys 
        join t in db.PowerStrings on p.string_id equals t.id 
        join u in db.PowerCombiners on t.combiner_id equals u.id 
        join s in db.PowerCombinerHistorys on p.recordTime equals s.recordTime 
        where p.recordTime >= UTC_StartingDate 
        where p.recordTime <= UTC_EndingDate 
        select new 
        { 
         Combiner = u.id, 
         Current = p.current, 
         RecordTime = p.recordTime, 
         Voltage = s.voltage 
        }; 

Ahora necesito al grupo por el combinador y la hora, así que puede promediar la corriente y obtener el kwh para cada combinador para cada hora del intervalo de fechas especificado.

I necesidad de aplicar esta fórmula simple en la consulta de algún modo: (vatios por hora promedio)/1000 = Kwh

Entonces, ¿qué voy a terminar con algo como lo de abajo. Cualquier ayuda sería muy apreciada.

Combiner 1  03/19/2012 1:0:0  1.85 Kwh 
Combiner 1  03/19/2012 2:0:0  1.98 Kwh 
Combiner 1  03/19/2012 3:0:0  2.05 Kwh 
Combiner 1  03/19/2012 4:0:0  2.11 Kwh 
Combiner 1  03/19/2012 5:0:0  2.01 Kwh 
Combiner 1  03/19/2012 6:0:0  1.96 Kwh 
Combiner 1  03/19/2012 7:0:0  1.85 Kwh 
Combiner 2  03/19/2012 1:0:0  1.77 Kwh 
Combiner 2  03/19/2012 2:0:0  1.96 Kwh 
Combiner 2  03/19/2012 3:0:0  2.03 Kwh 
Combiner 2  03/19/2012 4:0:0  2.11 Kwh 
Combiner 2  03/19/2012 5:0:0  2.02 Kwh 
Combiner 2  03/19/2012 6:0:0  1.98 Kwh 
Combiner 2  03/19/2012 7:0:0  1.83 Kwh 
Combiner 3  03/19/2012 1:0:0  1.77 Kwh 
Combiner 3  03/19/2012 2:0:0  1.96 Kwh 
Combiner 3  03/19/2012 3:0:0  2.03 Kwh 
Combiner 3  03/19/2012 4:0:0  2.11 Kwh 
Combiner 3  03/19/2012 5:0:0  2.02 Kwh 
Combiner 3  03/19/2012 6:0:0  1.98 Kwh 
Combiner 3  03/19/2012 7:0:0  1.83 Kwh 

EDITAR

anterior fue mi pregunta original. Después de trabajar con las dos sugerencias que recibí, terminé con el código que se muestra a continuación. Ahora mismo estoy devolviendo las fechas y el total de Kwh a la vista. Planeo lanzar la lista stringGroupedKwhlist en un HighChart para que el usuario vea y arroje los primeros resultados de la consulta Q a una grilla de Telerik para que el usuario filtre/ordene/agrupe para que pueda trabajar con los detalles. Si bien el código funciona y produce el resultado que estoy esperando, no estoy seguro de que sea eficiente. Como tengo que pasar por el uso de un foreach, supongo que una vez que obtiene una gran cantidad de datos podría ralentizarse. ¿Hay una manera más eficiente de manejar esto?

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Web.Mvc; 
using AESSmart.Models; 

namespace AESSmart.Controllers 
{ 
    public class StringKwh 
    { 
     public int CombinerID; 
     public int StringID; 
     public DateTime Interval; 
     public Double KWH; 

     public StringKwh(int combiner, int stringid, DateTime interval, double kwh) 
     { 
      CombinerID = combiner; 
      StringID = stringid; 
      Interval = interval; 
      KWH = kwh; 
     } 
    } 

    public class HomeController : Controller 
    { 
     private readonly AESSmartEntities db = new AESSmartEntities(); 

     public ActionResult Index() 
     { 
      //REPRESENTS DATE RANGE FOR A FULL DAY 
      DateTime startingDate = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, 0, 0, 1); 
      DateTime endingDate = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, 23, 59, 59); 

      TimeZoneInfo easternZone = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time"); 
      DateTime utcStartingDate = TimeZoneInfo.ConvertTimeToUtc(startingDate, easternZone); 
      DateTime utcEndingDate = TimeZoneInfo.ConvertTimeToUtc(endingDate, easternZone); 

      var firstQ = from p in db.PowerStringHistorys 
         from s in db.PowerCombinerHistorys 
         join t in db.PowerStrings on p.string_id equals t.id 
         join u in db.PowerCombiners on t.combiner_id equals u.id 
         where p.recordTime == s.recordTime 
         where p.recordTime >= utcStartingDate 
         where p.recordTime <= utcEndingDate 
         select new 
         { 
          Combiner = u.id, 
          StringId = p.string_id, 
          Current = p.current, 
          RecordTime = p.recordTime, 
          Voltage = s.voltage 
         }; 

      var groups = firstQ.ToList().GroupBy(q => new 
               { 
                q.Combiner, 
                q.StringId, 
                Date = q.RecordTime.Date, 
                Hour = q.RecordTime.Hour 
               }); 

      List<StringKwh> stringGroupedKwhlist = new List<StringKwh>(); 

      foreach (var group in groups) 
      { 
       stringGroupedKwhlist.Add(new StringKwh(
             group.Key.Combiner, 
             group.Key.StringId, 
             new DateTime(group.Key.Date.Year, group.Key.Date.Month, group.Key.Date.Day, group.Key.Hour, 0, 0), 
             group.Average(g => g.Voltage * g.Current)/1000d 
             )); 
      } 

      var groupCombiner = stringGroupedKwhlist.GroupBy(q => new { q.CombinerID }); 
      double myTotalKwh = 0; 

      foreach (var combinerGroup in groupCombiner) 
      { 
       myTotalKwh = Math.Round(combinerGroup.Sum(g => g.KWH), 3); 
      } 

      ViewBag.LifeTimeGeneration = myTotalKwh; 
      ViewBag.myUTCStartDate = utcStartingDate; 
      ViewBag.myUTCEndDate = utcEndingDate; 

      return View(); 
     } 

     public ActionResult About() 
     { 
      return View(); 
     } 
    } 
} 

Respuesta

11

Esto podría empezar:

// Group by combiner ID, date, and hour 
var groups = FirstQ.ToList() 
    .GroupBy(q => new 
     { q.Combiner, Date = q.RecordTime.Date, Hour = q.RecordTime.Hour }); 

foreach (var group in groups) 
{ 
    var combinerId = group.Key.Combiner; 
    var interval = new DateTime(group.Key.Date.Year, group.Key.Date.Month, group.Key.Date.Day, group.Key.Hour, 0, 0); 

    // power = voltage * current 
    var kwh = group.Average(g => g.Voltage * g.Current)/1000d; 
} 
+0

Gracias por la respuesta. De hecho, olvidé mencionar que también necesitaba agruparme por el nivel de cuerda. Entonces agregué eso. Logré que tu solución funcionara; sin embargo, tengo una preocupación. Por favor, revisa mi edición anterior. – Linger

2

sustituya el select con un groupby de la siguiente manera:

TimeZoneInfo easternZone = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time"); 
    DateTime UTC_StartingDate = TimeZoneInfo.ConvertTimeToUtc(StartingDate, easternZone); 
    DateTime UTC_EndingDate = TimeZoneInfo.ConvertTimeToUtc(EndingDate, easternZone); 

    var FirstQ = from p in db.PowerStringHistorys 
       join t in db.PowerStrings on p.string_id equals t.id 
       join u in db.PowerCombiners on t.combiner_id equals u.id 
       join s in db.PowerCombinerHistorys on p.recordTime equals s.recordTime 
       where p.recordTime >= UTC_StartingDate 
       where p.recordTime <= UTC_EndingDate 
       group new 
       { 
        Combiner = u.id, 
        Current = p.current, 
        RecordTime = p.recordTime, 
        Voltage = s.voltage 
       } 
       by new 
       { 
        Combiner = u.id, 
        Date = p.RecordTime.Date, 
        Hour = p.RecordTime.Hour 
       }; 
+0

Si hace esto, las lecturas en días diferentes en la misma hora se agruparán juntos; también deberá trabajar la fecha en la agrupación. Además, no estoy seguro de si .Hour funcionará para todos los proveedores de datos; esto puede causar problemas cuando llegue a SQL Server. –

+0

Gracias por la respuesta. No pude lograr que tu solución funcionara. No sabe qué hacer con q. Me gustaría poder realizar todo el trabajo dentro de la consulta. Creo que esa sería la forma más eficiente de manejarlo. – Linger

+0

@ToddGrover: escribí esto un poco demasiado rápido: tomé el grupo por su código y lo agregué al final del 'FirstQ' sin cambiar la variable lambda. Actualizaré esto para que coincida con las variables de rango presentes. Desafortunadamente, creo que me perdí el resto del código en desplazamiento, por lo que esto se detendrá con las proyecciones finales que querías; sin embargo, esto también podría lograrse con consultas continuas (es decir, la palabra clave 'into') y alguna más sintaxis de comprensión de consultas. Voy a actualizar para al menos tener esperanza de estar libre de errores de sintaxis. – devgeezer