MVC 4 Web API コントローラーに次のメソッドがあります。
public JsonResult GetJourney(List<string> assetIds, DateTime start, DateTime finish)
{
var journey = new List<JourneyPoint>();
var startUTC = start.ToUniversalTime();
var finishUTC = finish.ToUniversalTime();
foreach (var assetId in assetIds)
{
string id = assetId;
var events = _eventRepo.GetAll().Where(evt => evt.EventTypeId == 0 && evt.TimeStamp > startUTC && evt.TimeStamp < finishUTC && evt.AssetId == id);
foreach (var @event in events)
{
var myGps = _gpsRepo.GetAll().FirstOrDefault(gps => gps.Id == @event.GPSId);
if (myGps != null)
{
var myJourneyPoint = new JourneyPoint
{
Id = @event.Id,
AssetId = @event.AssetId,
TimeStamp = @event.TimeStamp.ToUnixEpocSeconds(),
Lat = myGps.Lat,
Long = myGps.Long,
Speed = myGps.Speed,
Elevation = myGps.Elevation,
Heading = myGps.Head
};
journey.Add(myJourneyPoint);
}
}
}
var jsonJourney = Json(journey.OrderBy(ju => ju.TimeStamp).ToList());
jsonJourney.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
return jsonJourney;
}
レポメソッドを次のように使用します。
public IQueryable<Event> GetAll()
{
var db = new CasLogEntities();
return db.Event;
}
public IQueryable<GPS> GetAll()
{
var db = new CasLogEntities();
return db.GPS;
}
これはすべてうまく機能し、リポジトリを使用することで、コントローラー コードのテスト スイートを作成することができました。
データベースへの複数の呼び出しがあり、SQL サーバーではなく .Net によって多くの計算作業が行われているという点で、このコードは非効率的であると思います。
Re-sharper は、for each ループを linq ステートメントに変換できることを提案しました。これを実行すると、次のコードになりました。
public JsonResult GetJourney(List<string> assetIds, DateTime start, DateTime finish)
{
var journey = new List<JourneyPoint>();
var startUTC = start.ToUniversalTime();
var finishUTC = finish.ToUniversalTime();
foreach (var assetId in assetIds)
{
string id = assetId;
var events = _eventRepo.GetAll().Where(evt => evt.EventTypeId == 0 && evt.TimeStamp > startUTC && evt.TimeStamp < finishUTC && evt.AssetId == id);
journey.AddRange(from @event in events
let myGps = _gpsRepo.GetAll().FirstOrDefault(gps => gps.Id == @event.GPSId)
where myGps != null
select new JourneyPoint
{
Id = @event.Id,
AssetId = @event.AssetId,
TimeStamp = @event.TimeStamp.ToUnixEpocSeconds(),
Lat = myGps.Lat,
Long = myGps.Long,
Speed = myGps.Speed,
Elevation = myGps.Elevation,
Heading = myGps.Head
});
}
var jsonJourney = Json(journey.OrderBy(ju => ju.TimeStamp).ToList());
jsonJourney.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
return jsonJourney;
}
ただし、このコードを実行するとエラーが発生します。
LINQ to Entities はメソッド 'System.Linq.IQueryable`1[CasWeb.Models.DataContext.GPS] GetAll()' メソッドを認識せず、このメソッドをストア式に変換できません。
これは、LINQ To Entities が "GetAll()" メソッドを sql にマップしようとしていて、それができないためだと理解しています。
私の質問は、このエラーを回避し、できるだけ多くの作業を SQL サーバーで実行するようにコードを書き直すにはどうすればよいですか? 可能であれば、テストを可能にするためにリポジトリパターンを維持しますか?