查询中索引超出范围异常

发布于 2024-11-07 17:48:09 字数 1205 浏览 0 评论 0原文

每条路线都包含按特定顺序排列的位置。
例如: 纽约 -> LA与LA不同->纽约。
我想编写一个方法来获取位置数组并返回 true 或 false 无论是否存在具有相同位置和顺序的路线。
我需要使用 linq to 实体和实体框架(路由和位置是实体)来完成此操作。 这是我写的:

    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(); 时发生异常,并且异常抱怨 Where(x => x.Locations.ElementAt(i).LocationId == locationId);< /代码>。

each Route contains Locations in specific order.
For example:
NY -> LA is different from LA -> NY.
I would like to write a method that gets locations array and return true or false whether route with the same locations and order exists.
I need to do it using linq to entities and entity framework (Route and Location are entities).
Here is what I wrote:

    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;
    }

I get the following exception in the marked line:

Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index

What is the reason for this exception?

EDIT
The exception accurs when executing route = query.SingleOrDefault(); and the exception complains about Where(x => x.Locations.ElementAt(i).LocationId == locationId);.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

调妓 2024-11-14 17:48:09

我相信这个查询是完全错误的。首先,它不是 linq-to-entities 查询,也永远不会是,因为 linq-to-entities 无法使用索引。我认为比较有序序列必须在内存中执行= 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 游标来比较存储过程中的序列。

I believe this query is completely wrong. First of all it is not linq-to-entities query and it will never be because linq to entities is not able to work with indexes. I think comparing ordered sequences will have to be executed in memory = linq-to-objects.

Another problem is this:

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();

I think this is known gotcha when using Linq, query built in loop and deferred execution - I believe this always compares locationId with the last element.

In my opinion the most efficient way to do this is stored procedure with table valued parameter passing your expected sequence and using SQL cursor to compare sequences in the stored procedure.

洋洋洒洒 2024-11-14 17:48:09

看起来您的 x.Locations.Count() 可能小于您的locationsInRoute.Count。你确定不是吗?我是说 b/c 你正在调用 x.Locations.ElementAt(i),如果 i > ,它将抛出异常。数数()。

作为旁注,您正在做的事情的更好解决方案是覆盖相等性或在您想要唯一的类上实现 IComparer,然后您可以使用 Any() 和 Contains() 等内容进行测试。

Looks like perhaps your x.Locations.Count() might be less than your locationsInRoute.Count. are you sure it's not? I'm saying that b/c you're calling x.Locations.ElementAt(i), which will throw if i > Count().

As a sidenote, a better solution to what you're doing is to override equality or implement an IComparer on your class that you want unique and then you can use things like Any() and Contains() for your test.

喜爱纠缠 2024-11-14 17:48:09

如果出现索引超出范围异常,则一定意味着locationsRoute 集合中的元素数量超过了IQueryable 中的元素数量。如果您尝试测试提供的列表中的每个位置是否包含在路线中,您应该能够执行以下操作:

var locationIds = locationsInRoute.Select(l => l.LocationId);
query = query.Where(r => r.Locations.All(l => locationIds.Contains(l.LocationId)))

If you getting an index out of range exception it must mean that number of elements in the locationsRoute collection exceeds the number of elements in IQueryable. If you attempting to test that each location in the provided list is contained in route you should be able to do something like:

var locationIds = locationsInRoute.Select(l => l.LocationId);
query = query.Where(r => r.Locations.All(l => locationIds.Contains(l.LocationId)))
街角卖回忆 2024-11-14 17:48:09

我猜这与您使用 ElementAt 有关,这不可能翻译为 SQL(请参阅“无翻译的运算符”部分),以对 IQueryable 进行操作。这会在第一次迭代中具体化 IQueryable 的结果集,因此后续迭代的 Route 项将无法访问其相关的 Locations 集。这可能只发生在第二次迭代上,但在任何情况下我都不完全清楚 LINQ 延迟执行性质的无数含义;-) HTH

您可以在 SingleOrDefault 处放置一个断点并检查它在那里执行的 SQL 语句,看看为什么没有返回记录供 SingleOrDefault 查找。尽管 SQL 可能相当难看,具体取决于您有多少条路线。

I'm guessing it has to do with your use of ElementAt, which can't be translated to SQL (see the Operators with No Translation section), to operate on your IQueryable. This materializes the IQueryable's result set on the first iteration and so subsequent iterations Route items will be unable to access their related Locations sets. This should probably only happen on the second iteration, but the myriad implications of the deferred execution nature of LINQ is not entirely clear to me in ever case ;-) HTH

You could put a breakpoint at SingleOrDefault and inspect the SQL statement it is executing there, to see why there is no record returned for the SingleOrDefault to find. Though the SQL may be pretty ugly depending on how many routes you have.

梦境 2024-11-14 17:48:09

感谢@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;
    }

Thanks to @Ladislav Mrnka's advice, here is the solution:

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;
    }
戏剧牡丹亭 2024-11-14 17:48:09

如果位置具有您上面指出的顺序,则可以完全在(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;
}

If Location has Order as you indicate above, this can be done entirely in (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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文