Why this Linq code always throws System.StackOverf

2019-05-28 16:58发布

问题:

 //A query to a local object
 var deletionCommands = commands
     .Where(a => a.Operation != Operation.Addition)
     .Select(a => new { a.Prestador.cod_prestador, a.Prestador.cod_desdobramento })
     ;
 //A Linq-To-SQL query
 var toDelete = db.Prestadors
     .Where(a => deletionCommands.Contains(new { a.cod_prestador, a.cod_desdobramento }))
     ;
 db.Prestadors.DeleteAllOnSubmit(toDelete);
 db.SubmitChanges();

The only thing that solved the problem was an explicit loop:

 foreach (var command in commands)
 {
    if(command.Operation != Operation.Addition)
    {
        var toDelete = db.Prestadors
            .Where(a =>
                a.cod_prestador == command.Prestador.cod_prestador &&
                a.cod_desdobramento == command.Prestador.cod_desdobramento
            );
        db.Prestadors.DeleteAllOnSubmit(toDelete);
    }
 }
 db.SubmitChanges();

回答1:

That was really a bug, and was corrected in LINQ 4.0

http://damieng.com/blog/2009/06/01/linq-to-sql-changes-in-net-40

Query stability Contains now detects self-referencing IQueryable and doesn't cause a stack overflow

EDIT In .NET 3.5 to resolve the problem: When using 'Auto Generated Value' = True, then you must set 'Delay Loaded' to False - otherwise you get the recursion error.

EDIT2 The solution above didn't work.



回答2:

Put a breakpoint on the last line, then run the code. Then when it stops on the breakpoint, add another breakpoint at the start of that chunk of code. Then continue in the debugger (step over). It should hit the new breakpoint, and you can examine the stack to see how it has called back on itself.

What's the implementation of the Operation property? Maybe that calls back into some other code in a recursive way.



回答3:

I know this is an old post already, but changing the Contains method to Equals worked for me also.

This fails with StackOverflowException

Dim iLottery As IEnumerable(Of Lottery) = From lottery2 In combined2 Where Not (From lottery1 In combined Select lottery1.NUMBER).Contains(lottery2.NUMBER) Select lottery2

This does not

Dim iLottery As IEnumerable(Of Lottery) = From lottery2 In combined2 Where Not (From lottery1 In combined Select lottery1.NUMBER).Equals(lottery2.NUMBER) Select lottery2