3

My current method looks like this inside an MVC controller:

public async Task<IActionResult> AddTests(int? batchId, int? batchVersion)
{
    var btu_DatabaseContext = _context.Test;
    var tests = from info in btu_DatabaseContext select info;
    var btu_DatabaseContext2 = _context.BatchTest;
    var batchTests = from info in btu_DatabaseContext2 select info;
    batchTests = batchTests.Where(s => (s.BatchId == batchId && s.BatchVersion == batchVersion));

    foreach(var batchTest in batchTests)
    {
        tests = tests.Where(s => s.BatchTest != batchTest);
    }
        


    ViewData["BatchId"] = batchId;
    ViewData["BatchVersion"] = batchVersion;
    if(tests != null && tests.Any())
    {
        return View(tests);
    }

    return RedirectToAction(nameof(Edit), new { id = batchId, version = batchVersion, message = "No unused tests." });
}

If I call it in a situation where the foreach loop removes all the elements of tests I always get the following error:

An unhandled exception occurred while processing the request.

ArgumentNullException: Value cannot be null.

Parameter name: querySource

Before I added the if statement the code would break on the return. I added in the if statement at the end to attempt to check if tests was null or empty, but this doesn't seem to work; the code now breaks when tests.Any() is called.

What is the appropriate way to check if tests is null/empty in order to avoid this error?

Update

Here is the full stack trace:

System.ArgumentNullException: Value cannot be null.
Parameter name: querySource
at Microsoft.EntityFrameworkCore.Utilities.Check.NotNull[T](T value, String parameterName)
at Microsoft.EntityFrameworkCore.Query.QueryCompilationContext.FindEntityType(IQuerySource querySource)
at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.RelationalEntityQueryableExpressionVisitor.VisitEntityQueryable(Type elementType)
at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.EntityQueryableExpressionVisitor.VisitConstant(ConstantExpression constantExpression)
at System.Linq.Expressions.ConstantExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at System.Linq.Expressions.ExpressionVisitor.VisitUnary(UnaryExpression node)
at System.Linq.Expressions.UnaryExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at System.Linq.Expressions.ExpressionVisitor.Visit(ReadOnlyCollection`1 nodes)
at System.Linq.Expressions.ExpressionVisitor.VisitNewArray(NewArrayExpression node)
at System.Linq.Expressions.NewArrayExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at System.Linq.Expressions.ExpressionVisitor.VisitAndConvert[T](ReadOnlyCollection`1 nodes, String callerName)
at Remotion.Linq.Parsing.RelinqExpressionVisitor.VisitNew(NewExpression expression)
at System.Linq.Expressions.NewExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at System.Linq.Expressions.ExpressionVisitor.VisitBinary(BinaryExpression node)
at System.Linq.Expressions.BinaryExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.ReplaceClauseReferences(Expression expression, IQuerySource querySource, Boolean inProjection)
at Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.VisitWhereClause(WhereClause whereClause, QueryModel queryModel, Int32 index)
at Microsoft.EntityFrameworkCore.Query.RelationalQueryModelVisitor.VisitWhereClause(WhereClause whereClause, QueryModel queryModel, Int32 index)
at Remotion.Linq.Clauses.WhereClause.Accept(IQueryModelVisitor visitor, QueryModel queryModel, Int32 index)
at Remotion.Linq.QueryModelVisitorBase.VisitBodyClauses(ObservableCollection`1 bodyClauses, QueryModel queryModel)
at Remotion.Linq.QueryModelVisitorBase.VisitQueryModel(QueryModel queryModel)
at Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.VisitQueryModel(QueryModel queryModel)
at Microsoft.EntityFrameworkCore.Query.RelationalQueryModelVisitor.VisitQueryModel(QueryModel queryModel)
at Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.CreateQueryExecutor[TResult](QueryModel queryModel)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.CompileQueryCore[TResult](Expression query, INodeTypeProvider nodeTypeProvider, IDatabase database, IDiagnosticsLogger`1 logger, Type contextType)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass15_0`1.<Execute>b__0()
at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQueryCore[TFunc](Object cacheKey, Func`1 compiler)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.Execute[TResult](Expression query)
at System.Linq.Queryable.Any[TSource](IQueryable`1 source)
at WebAppCore.Controllers.BatchesController.<AddTests>d__14.MoveNext() in C:\Users\Rex\Documents\School\Capstone\WebAp2\WebApp\Btu Database\WebAppCore\Controllers\BatchesController.cs:line 315
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.<InvokeActionMethodAsync>d__12.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.<InvokeNextActionFilterAsync>d__10.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context)
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.<InvokeInnerFilterAsync>d__14.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.<InvokeNextResourceFilter>d__22.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context)
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.<InvokeFilterPipelineAsync>d__17.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.<InvokeAsync>d__15.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNetCore.Builder.RouterMiddleware.<Invoke>d__4.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.<Invoke>d__7.MoveNext()

I'm using Microsoft.AspNetCore.All v2.0.6 and Microsoft.EntityFrameworkCore v2.0.2.

Community
  • 1
  • 1
Rex Rogers
  • 41
  • 4
  • Why not do one query instead of two `from t in _context.Test where t.BatchTest.BatchId != batchId || t.BatchTest.BatchVersion != batchVersion select t;` – juharr Mar 31 '18 at 02:49
  • The query source here would be `btu_DatabaseContext`, did you check if that was null? – juharr Mar 31 '18 at 02:58
  • That's what I tried to do initially, but it gives an error: "'ICollection' does not contain a definition for 'batchId' and no extension method 'batchId' accepting a first argument of type 'ICollection' could be found (are you missing a using directive or an assembly reference?) – Rex Rogers Mar 31 '18 at 03:03
  • @btu_DatabaseContext definitely is not null. – Rex Rogers Mar 31 '18 at 03:03
  • Wait if the `BatchTest` property is a collection then your code doesn't make sense because you compare that to a single `BatchTest` from the second query. – juharr Mar 31 '18 at 03:06
  • I was under the impression that I would end up with all `Test` entries that don't have any related `BatchTest` entries that have the `batchId` and `batchVersion`. I think I've successfully used `Where()` like this before, but maybe I'm not remembering correctly. – Rex Rogers Mar 31 '18 at 03:18
  • If you're using Entity Framework Core, these issues might be related: https://github.com/aspnet/EntityFrameworkCore/search?utf8=%E2%9C%93&q=%22Parameter+name%3A+querySource%22&type=Issues – Shaun Luttin Mar 31 '18 at 03:55
  • Also, can you please post the entire stack trace of the exception that you're receiving. That would help troubleshooting. – Shaun Luttin Mar 31 '18 at 03:56
  • Out of curiosity, what happens if you do this: `var btu_DatabaseContext = _context.Test.Include(t => t.BatchTest).ToList();` to load the related entities explicitly? – Shaun Luttin Mar 31 '18 at 03:59
  • As far as I can tell, the `foreach` loop looks very suspicious. Please provide the full exception stack trace. Also specify the exact EF version. – Ivan Stoev Mar 31 '18 at 10:38

1 Answers1

0

I like to use this extension method in conjunction with the null object pattern to ensure if I do get a null from a LINQ query I don't get any surprise exceptions.

var items = listOfItems.FirstOrDefault().IfDefaultGiveMe(new NullItem());
Mitch Stewart
  • 1,253
  • 10
  • 12
  • Why not just `var item = listOfItems.FirstOrDefault() ?? new NullTime();`? Assuming you're not dealing with a struct of value type. – juharr Mar 31 '18 at 02:53
  • That would work too. I like the IfDefaultGiveMe extension method because it guards against nulls and defaults. This looks like a good option too (https://stackoverflow.com/questions/65351/null-or-default-comparison-of-generic-argument-in-c-sharp). – Mitch Stewart Mar 31 '18 at 03:05