[英]Index was out of range exception in query
每条路线均按特定顺序包含位置。
例如:NY-> LA与LA-> NY不同。
我想编写一个获取位置数组并返回true或false的方法,而该方法是否存在具有相同位置和顺序的路由。
我需要使用linq来实现实体和实体框架(Route和Location是实体)。 这是我写的:
public bool IsRouteExists(IList<LocationInRoute> locationsInRoute)
{
Route route = null;
if (locationsInRoute.Count > 0)
{
var query = GetRoutesQuery().
Where(x => x.Locations.Count() == locationsInRoute.Count);
for (int i = 0; i < locationsInRoute.Count; i++)
{
long locationId = locationsInRoute[i].LocationId;
query = query.Where(x =>
x.Locations.ElementAt(i).LocationId == locationId); //THROWS EXCEPTION
}
route = query.SingleOrDefault();
}
return route!=null;
}
我在标记的行中收到以下异常:
Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index
发生此异常的原因是什么?
编辑
执行route = query.SingleOrDefault();
时会发生异常route = query.SingleOrDefault();
并且异常抱怨Where(x => x.Locations.ElementAt(i).LocationId == locationId);
。
我相信这个查询是完全错误的。 首先,它不是linq-to-entities查询,并且永远不会因为linq to实体无法使用索引。 我认为比较有序序列将必须在memory = linq-to-objects中执行。
另一个问题是:
for (int i = 0; i < locationsInRoute.Count; i++)
{
long locationId = locationsInRoute[i].LocationId;
query = query.Where(x => x.Locations.ElementAt(i).LocationId == locationId);
}
route = query.SingleOrDefault();
我认为使用Linq,在循环中建立查询和推迟执行时这是已知的陷阱 -我相信这总是将locationId
与最后一个元素进行比较。
在我看来,最有效的方法是使用表值参数传递您期望的序列并使用SQL游标比较存储过程中的序列的存储过程。
看起来您的x.Locations.Count()可能小于您的locationsInRoute.Count。 您确定不是吗? 我是说b / c您正在调用x.Locations.ElementAt(i),如果i> Count()会抛出该错误。
附带说明,一种更好的解决方案是重写相等性或在要唯一的类上实现IComparer,然后可以使用Any()和Contains()之类的东西进行测试。
如果索引超出范围异常,则必须表示locationsRoute集合中的元素数超过了IQueryable中的元素数。 如果尝试测试提供的列表中的每个位置都包含在路由中,则应该可以执行以下操作:
var locationIds = locationsInRoute.Select(l => l.LocationId);
query = query.Where(r => r.Locations.All(l => locationIds.Contains(l.LocationId)))
我猜想这与您对ElementQuery的使用有关,后者不能转换为SQL (请参阅“无转换的运算符”部分),以对IQueryable进行操作。 这将在第一次迭代中实现IQueryable的结果集,因此后续迭代Route项将无法访问其相关的Locations集。 这可能只应该在第二次迭代中发生,但是在任何情况下,LINQ的延迟执行本质所带来的诸多影响在我看来都不是完全清楚;-) HTH
您可以在SingleOrDefault处放置一个断点,并检查在该处执行的SQL语句,以查看为什么没有返回任何记录供SingleOrDefault查找。 尽管SQL可能很难看,具体取决于您拥有多少条路由。
感谢@Ladislav Mrnka的建议,以下是解决方案:
public class LocationSequenceEqual : IEqualityComparer<Location>
{
public bool Equals(Location x, Location y)
{
return x.Id == y.Id;
}
public int GetHashCode(Location obj)
{
return obj.Id.GetHashCode();
}
}
public bool IsRouteExists(IList<LocationInRoute> locationsInRoute)
{
Route route = null;
if (locationsInRoute.Count > 0)
{
var query = GetRoutesQuery().
Where(x => x.Locations.Count() == locationsInRoute.Count);
query = query.Where(x => x.Locations.OrderBy(l => l.Order).
Select(l => l.Location).SequenceEqual(locations, new LocationSequenceEqual()));
route = query.FirstOrDefault();
}
return route!=null;
}
如果“位置”具有上面所指定的“顺序”, 则可以完全在(Linq to)SQL中完成:
public bool IsRouteExists(IList<LocationInRoute> locationsInRoute)
{
Route route = null;
if (locationsInRoute.Count == 0)
return;
var possibleRoutes = GetRoutesQuery().
Where(x => x.Locations.Count() == locationsInRoute.Count);
var db = GetDataContext(); //get a ref to the DataContext or pass it in to this function
for (var i = 0; i < locationsInRoute.Length; i++)
{
var lcoationInRoute = locationsInRoute[i];
possibleRoutes = possibleRoutes.Where(x => x.Locations.Any(l => l.Id == locationInRoute.Id && l.Order == locationInRoute.Order));
}
route = possibleRoutes.FirstOrDefault();
return route!=null;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.