Хорошо, обычно в SQL мы будем использовать LEAD / LAG
оконные функции для выполнения таких функций. Но поскольку нет простого способа использовать LEAD / LAG
в Entity Framework без использования библиотеки, такой как MoreLinq
или Linq2DB
, я предложил следующее решение в одном из моих существующих проектов.
List<TestModel> logs = new List<TestModel>();
logs.Add(new TestModel() { A_id = 1, DeviceImei = "234", DeviceTimeStamp = DateTime.Now.AddDays(-2), KWH = 50 });
logs.Add(new TestModel() { A_id = 2, DeviceImei = "234", DeviceTimeStamp = DateTime.Now.AddDays(-2).AddSeconds(2), KWH = 50 });
logs.Add(new TestModel() { A_id = 3, DeviceImei = "234", DeviceTimeStamp = DateTime.Now.AddDays(-2).AddSeconds(3), KWH = 650 });
logs.Add(new TestModel() { A_id = 4, DeviceImei = "234", DeviceTimeStamp = DateTime.Now.AddDays(-2).AddSeconds(4), KWH = 90 });
logs.Add(new TestModel() { A_id = 5, DeviceImei = "234", DeviceTimeStamp = DateTime.Now.AddDays(-2).AddSeconds(5), KWH = 20 });
logs.Add(new TestModel() { A_id = 6, DeviceImei = "234", DeviceTimeStamp = DateTime.Now.AddDays(-2).AddSeconds(6), KWH = 50 });
string imei = "234";
DateTime sd = DateTime.Today.AddDays(-3);
DateTime ed = DateTime.Today.AddDays(1);
var response = from locationLog in logs
.Where(s => s.DeviceImei == imei && s.DeviceTimeStamp >= sd && s.DeviceTimeStamp <= ed)
.OrderBy(t => t.DeviceTimeStamp)
// get the previous log from locationLog
let prevLog = logs
.Where(s => s.DeviceImei == imei
&& s.DeviceTimeStamp >= sd
&& s.DeviceTimeStamp <= ed
&& s.DeviceTimeStamp <= locationLog.DeviceTimeStamp
&& s.A_id != locationLog.A_id)
.OrderByDescending(s => s.DeviceTimeStamp)
.FirstOrDefault()
orderby locationLog.DeviceTimeStamp
select new
{
A_id = locationLog.A_id,
DeviceImei = locationLog.DeviceImei,
DeviceTimeStamp = locationLog.DeviceTimeStamp,
KWH = locationLog.KWH,
prevId = prevLog != null ? prevLog.A_id : -1,
KWH_I = prevLog != null ? locationLog.KWH - prevLog.KWH : 0
};
При переводе на SQL это будет означать запрос OUTER APPLY
SQL.