2

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 サーバーで実行するようにコードを書き直すにはどうすればよいですか? 可能であれば、テストを可能にするためにリポジトリパターンを維持しますか?

4

1 に答える 1

1

@Rup がコメントで示唆しているように、次のようにしてエラーを回避する必要があります。

    journey.AddRange(from @event in events
                 join gps in _gpsRepo.GetAll() on gps.Id == @event.GPSId
                 select new JourneyPoint
                 {
                     Id = @event.Id,
                     AssetId = @event.AssetId,
                     TimeStamp = @event.TimeStamp.ToUnixEpocSeconds(),
                     Lat = gps.Lat,
                     Long = gps.Long,
                     Speed = gps.Speed,
                     Elevation = gps.Elevation,
                     Heading = gps.Head
                 });
于 2013-01-21T01:53:42.620 に答える