Reputation: 18765
This code works ok, but I was wondering whether there isn't some way to write it in one LINQ expression so a single pass can be done by the database server instead of realising a result set and then looping through it, which is what my code will produce.
var logs = from AssetLog log in dc.AssetLogs
where log.AssetId == assetId && log.Recorded >= start && log.Recorded <= finish
select log;
return new GetInteractionBoundsResult()
{
N = logs.Max(log => log.Latitude),
S = logs.Min(log => log.Latitude),
W = logs.Min(log => log.Longitude),
E = logs.Max(log => log.Longitude)
};
So, LINQ gurus, how would you write the above so that it produces more or less this at the database:
SELECT MIN(Latitude) S, MAX(Latitude) N, MIN(Longitude) W, MAX(Longitude) E
FROM ASSETLOG WHERE etc etc
Upvotes: 1
Views: 62
Reputation: 156524
Sure, just trick your LINQ provider into thinking it's still working with a query until the very end:
var logs = from asset in dc.Assets
where asset.AssetId == assetId
let g = asset.AssetLogs
.Where(log => log.Recorded >= start && log.Recorded <= finish)
select new GetInteractionBoundsResult
{
N = g.Max(log => log.Latitude),
S = g.Min(log => log.Latitude),
W = g.Min(log => log.Longitude),
E = g.Max(log => log.Longitude)
};
return logs.Single();
A Group By may perform better than the join that the above query would produce:
var logs = from log in dc.AssetLogs
where log.AssetId == assetId &&
log.Recorded >= start && log.Recorded <= finish
group log by log.AssetId into g
select new GetInteractionBoundsResult
{
N = g.Max(log => log.Latitude),
S = g.Min(log => log.Latitude),
W = g.Min(log => log.Longitude),
E = g.Max(log => log.Longitude)
};
return logs.Single();
Upvotes: 1
Reputation: 77540
It would take a pretty sophisticated LINQ provider, but a subquery may work:
var res = from asset in dc.Assets
where log.AssetId == assetId
let logs = (from AssetLog log in asset.AssetLogs
where log.Recorded >= start && log.Recorded <= finish
select log)
select new GetInteractionBoundsResult()
{
N = logs.Max(log => log.Latitude),
S = logs.Min(log => log.Latitude),
W = logs.Min(log => log.Longitude),
E = logs.Max(log => log.Longitude)
};
return res.Single();
Upvotes: 0