[英]LINQ /Entity Framework complex query: take all rows
首先,請原諒我的頭銜,因為我找不到我要解決的問題的有意義的頭銜。
我有3個表,“公司”,“設備”和“度量值”,一個公司可以有很多設備,而“度量”表每5分鍾具有每個設備的溫度數據。
問題是:
我需要執行一個使我返回的LINQ / EF查詢:1.每個公司每個設備的最新溫度。
因此,如果您看到圖片中的表格,它將返回以下內容:
我在C#中的模型是這樣的:
public class Medida
{
[Key]
[DisplayName("Medida")]
public int MedidaID { get; set; }
public decimal Temperatura { get; set; }
public int Humedad { get; set; }
public DateTime FechaHora { get; set; }
[DisplayName("Dispositivo")]
public int DispositivoID { get; set; }
public virtual Dispositivo Dispositivo { get; set; }
}
設備:
[Table("Dispositivo")]
public class Dispositivo //
{
[Key]
[Column(Order = 0)]
public int DispositivoID { get; set; }
[StringLength(100)]
[Required(ErrorMessage = "El nombre es requerido")]
public string Nombre { get; set; }
public string ClaveDispositivo { get; set; }
public bool Activo { get; set; }
[Required(ErrorMessage = "El nombre Empresa es requerido")]
[Display(Name = "Empresa")]
public int EmpresaID { get; set; }
public virtual Empresa Empresa { get; set; }
public virtual ICollection<Medida> Medidas { get; set; }
}
}
和公司表
public partial class Empresa
{
[Key] //clave primaria en la tabla
[Display(Name = "Empresa")]
public int EmpresaID { get; set; }//metodos de acceso de lectura y escritura a la propiedad
[StringLength(100)] // no debe pasarse de 100 caracteres
[Required(ErrorMessage = "El nombre empresa es requerido")]
[DisplayName("Nombre Empresa")]
public string Nombre { get; set; }
[StringLength(100)]
//[Required(ErrorMessage = "El código es requerido")]
[DisplayName("Código")]
public string Codigo { get; set; }
[Display(Name = "Correo")]
[Required(ErrorMessage = "El correo es requerido")]
[EmailAddress(ErrorMessage = "dirección de correo invalido")]
public string Correo { get; set; }
public bool Activo { get; set; }
public bool Notificar_Correo { get; set; }
public bool Notificar_SMS { get; set; }
public virtual ICollection<Dispositivo> Dispositivos { get; set; }
public virtual ICollection<Usuario> Usuarios { get; set; }
}
最后,這是我試圖在需要限制返回的行的地方實現的代碼:
public void TakeLastTemp()
{
using (ZigBeeContext db = new ZigBeeContext())
{
var lista = db.Medidas
.Include(e => e.Dispositivo);
您可以通過其FechaHora
datetime屬性以降序對測量進行排序,並采用第一個。
from e in db.Empresas
from d in e.Dispositivos
let lastMeasurement = d.Medidas.OrderByDescending(m => m.FechaHora)
.FirstOrDefault()
select new
{
Empresa = c.Nombre,
Dispositivo = d.Nombre,
lastMeasurement.FechaHora,
lastMeasurement. ... // etc.
}
請記住,整個LINQ語句已轉換為SQL,因此您不必擔心lastMeasurement.FechaHora
等中的空引用。唯一的問題是,如果存在沒有測量值的設備,則必須將非空類型轉換為可空:
(DateTime?)lastMeasurement.FechaHora
我建議更改一下數據庫表結構,在設備表中添加其他字段LastTemperature,並更改更新表中溫度的代碼,在此表中添加新行並更新Device表中歸檔的LastTemperature的測量值,然后即可輕松查詢它與Linq。 它將簡化您的查詢。 有這個主意嗎?
如果首先在sql中決定查詢,然后考慮使用LINQ或EF實施,則總是很容易的。
可以從下面的SQL查詢中檢索圖像中表的結果。
SELECT m.* FROM dbo.Measures m
JOIN
(SELECT IdDevice,MAX(datetime) AS sdatetime FROM dbo.Measures
GROUP BY IdDevice) s
ON s.IdDevice = m.IdDevice AND m.[datetime] = s.sdatetime
在EF中,不能以這種方式完成include measure.include(device),因為它是根據表設計包含許多度量的設備。
由於所需數據來自度量表,因此可以按如下方式使用LINQ查詢。 我已經根據圖像使用了表名和列名。
var subquery = db1.Measures.GroupBy(row => new { id = row.IdDevice }).Select(Finalrow => new
{
IdDevice = Finalrow.Key.id,
datetime = Finalrow.Max(d => d.datetime)
});
var mainquery = db1.Measures.Join(subquery, m => m.IdDevice, s => s.IdDevice, (m, s) => new { m, s }).Where(deviceid => deviceid.m.datetime == deviceid.s.datetime).Select(Finalrow => new
{
id = Finalrow.m.IdMeasure,
temp = Finalrow.m.temp,
deviceid = Finalrow.m.IdDevice,
date = Finalrow.m.datetime
});
希望這可以幫助。 如有問題,請通知我。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.