在 linq 查询后检查实体是不是为空
Posted
技术标签:
【中文标题】在 linq 查询后检查实体是不是为空【英文标题】:Checking if an entity is null after linq queries在 linq 查询后检查实体是否为空 【发布时间】:2018-03-31 02:39:48 【问题描述】:我当前的方法在 MVC 控制器中如下所示:
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." );
如果我在 foreach 循环删除所有测试元素的情况下调用它,我总是会收到以下错误:
处理请求时发生未处理的异常。
ArgumentNullException:值不能为空。
参数名称:查询源
在我添加 if 语句之前,代码会在返回时中断。我在最后的 if 语句中添加了尝试检查测试是否为空或空,但这似乎不起作用;现在,当调用 tests.Any() 时,代码会中断。
为了避免这个错误,检查测试是否为空/空的适当方法是什么?
更新
这是完整的堆栈跟踪:
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()
我正在使用Microsoft.AspNetCore.All v2.0.6
和Microsoft.EntityFrameworkCore v2.0.2
。
【问题讨论】:
为什么不做一个查询而不是两个from t in _context.Test where t.BatchTest.BatchId != batchId || t.BatchTest.BatchVersion != batchVersion select t;
这里的查询源是btu_DatabaseContext
,你检查是否为空吗?
这就是我最初尝试做的,但它给出了一个错误:“'ICollectionBatchTest
属性是一个集合,那么您的代码没有意义,因为您将它与第二个查询中的单个 BatchTest
进行比较。
【参考方案1】:
我喜欢将 this 扩展方法与 null object pattern 结合使用,以确保如果我从 LINQ 查询中得到空值,我不会得到任何意外异常。
var items = listOfItems.FirstOrDefault().IfDefaultGiveMe(new NullItem());
【讨论】:
为什么不只是var item = listOfItems.FirstOrDefault() ?? new NullTime();
?假设您不处理值类型的结构。
这也行。我喜欢 IfDefaultGiveMe 扩展方法,因为它可以防止空值和默认值。这看起来也是一个不错的选择 (***.com/questions/65351/…)。以上是关于在 linq 查询后检查实体是不是为空的主要内容,如果未能解决你的问题,请参考以下文章