【发布时间】:2013-01-21 01:21:53
【问题描述】:
我在 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;
}
这一切都很好,并且使用存储库允许我为控制器代码编写一个测试套件。
虽然我怀疑这段代码效率低下,因为对数据库有多次调用,并且很多计算工作是由 .Net 而不是 sql server 完成的。
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 服务器执行尽可能多的工作?并尽可能维护存储库模式以进行测试?
【问题讨论】:
-
我想你想要一个
.Join -
.GetAll().Where(... 和 .GetAll.FirstOrDefault() 是对存储库模式的公然滥用,当然这不是你的问题。
-
嗨罗布里希。我认为您指的是结果集的过滤不是在存储库中完成的,而是在控制器中完成的。如果 repo 有一个 getbyID 和一个 getbyRange 方法会更好吗? getAll().Where(.. 是否也意味着整个集合都被返回并在 c# 中完成过滤?我怎样才能让这段代码更好/更高效?
标签: c# .net entity-framework-4 linq-to-entities