I'm trying to fetch the changed records, in which the Ignition of Vehicle Changed. Here is my SQL table.
ie I want to fetch record 47890 and and record 47879.
i've written the following correlated LINQ query.
var sData = (from log in db.GSMDeviceLogs
where log.Vehicle.VehicleId == vehicleId
where log.IgnitionOn != (from prevLog in db.GSMDeviceLogs
where prevLog.Vehicle.VehicleId == vehicleId
where prevLog.DateTimeOfLog < log.DateTimeOfLog
orderby prevLog.DateTimeOfLog descending
select prevLog.IgnitionOn).FirstOrDefault()
orderby log.DateTimeOfLog ascending
select new { LogId = log.GSMDeviceLogId,
Ignition = log.IgnitionOn,
Date = log.DateTimeOfLog,
Location = log.Location }).ToList();
It gives the following exception:
An exception of type 'System.Data.Entity.Core.EntityCommandExecutionException' occurred in EntityFramework.SqlServer.dll but was not handled in user code
Inner Exception Says:
{"Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding."}
I hope this is due to the query being very inefficient and taking too much time to execute. How can we optimize the LINQ query?
It is all right, you could probably do something more efficient with a nice sproc or some magic SQL. But let's say you can't, for whatever reason. It does not mean you have to either give up or run some SELECT N+1 code. If you properly order your sequence (as you are already doing) you can scan your sequence just once with Linq and use some smart extension method to remember the previous value. With something like this in your toolbox:
static class EnumerableExtensions
{
public static IEnumerable<TR> Pair<T, TR>(this IEnumerable<T> source, Func<T, T, TR> resultor)
{
return PairImpl<T, TR>(source, resultor);
}
static IEnumerable<TR> PairImpl<T, TR>(IEnumerable<T> source, Func<T, T, TR> resultor)
{
var e = source.GetEnumerator();
var a = default(T);
while (e.MoveNext())
{
var b = e.Current;
yield return resultor(a, b);
a = b;
}
}
}
You can then write an expression like this:
var logs =
from log in db.GSMDeviceLogs
where log.Vehicle.VehicleId == vehicleId
orderby log.DateTimeOfLog ascending
select log;
var diffs =
from log in logs.Pair((a, b) => new { a, b })
where log.a != null && log.a.IgnitionOn != log.b.IgnitionOn
select log.a;
This scans in memory all your records, but just once, and it does it in an expressive way. As said, doing it at the database level would be more efficient, but maybe you can't go there.
The MoreLinq project is packed with extension methods like the one I roughly suggest here.
Do a self join:
var sData = (from log in db.GSMDeviceLogs
join log2 in db.GSMDeviceLogs on log.GSMDeviceLogId equals log2.GSMDeviceLogId - 1
where log.Vehicle.VehicleId == vehicleId
&& log.IgnitionOn != log2.IgnitionOn
orderby log.DateTimeOfLog ascending
select new { LogId = log.,
Ignition = log.IgnitionOn,
Date = log.DateTimeOfLog,
Location = log.Location }).ToList();
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.