IQueryable使用Where子句抛出OutOfMemory异常

时间:2015-09-01 20:51:56

标签: c# entity-framework-4 breeze asp.net-web-api2 iqueryable

更新时间:2015年3月9日

好的,我试着改为.Join:

    [System.Web.Http.HttpGet]
    public IQueryable<RunOfferPublish> RunOfferPublishes()
    {
        var showIds = _showSecurityCache.GetRunIdsForCurrentUser().AsEnumerable();
        return Context.RunOfferPublishes.Join(showIds, r => r.RunOffer.Run.showId, i => i, (r, i) => r);
    }

我得到另一个例外,说我的查询嵌套到深。我做了一个方法来减少嵌套并获得runIds。但是,还有更多的ID ..

    [System.Web.Http.HttpGet]
    public IQueryable<RunOfferPublish> RunOfferPublishes()
    {
        var runIds = _showSecurityCache.GetRunIdsForCurrentUser().AsEnumerable();
        return Context.RunOfferPublishes.Join(runIds, r => r.RunOffer.RunId, i => i, (r, i) => r);
    }

我得到一个stackoverflow异常,有很多运行。

然后我尝试删除获取所有实体的侦听,并在内存中执行操作。像这样:

    [System.Web.Http.HttpGet]
    public IQueryable<RunOfferPublish> RunOfferPublishes()
    {
        var showIds = _showSecurityCache.GetShowIdsForCurrentUser();
        var list = Context.RunOfferPublishes.ToList();
        return list.Where(i => showIds.Contains(i.RunOffer.Run.ShowId)).AsQueryable();
    }

这“工作”,它返回实体列表。但是,我遇到了Breeze的问题

  

'System.Linq.EnumerableQuery'不包含'Include'的定义

at CallSite.Target(Closure , CallSite , Object , String )
at System.Dynamic.UpdateDelegates.UpdateAndExecute2[T0,T1,TRet](CallSite site, T0 arg0, T1 arg1)
at CallSite.Target(Closure , CallSite , Object , String )
at Breeze.WebApi.QueryHelper.<>c__DisplayClass14.<ApplyExpand>b__11(String expand)
at System.Collections.Generic.List`1.ForEach(Action`1 action)
at Breeze.WebApi.QueryHelper.ApplyExpand(IQueryable queryable, String expandsQueryString)
at Breeze.WebApi.QueryHelper.ApplySelectAndExpand(IQueryable queryable, NameValueCollection map)
at Breeze.WebApi.BreezeQueryableAttribute.OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
at System.Web.Http.Filters.ActionFilterAttribute.CallOnActionExecuted(HttpActionContext actionContext, HttpResponseMessage response, Exception exception)
at System.Web.Http.Filters.ActionFilterAttribute.<>c__DisplayClass2.<System.Web.Http.Filters.IActionFilter.ExecuteActionFilterAsync>b__0(HttpResponseMessage response)
at System.Threading.Tasks.TaskHelpersExtensions.<>c__DisplayClass41`2.<Then>b__40(Task`1 t)
at System.Threading.Tasks.TaskHelpersExtensions.ThenImpl[TTask,TOuterResult](TTask task, Func`2 continuation, CancellationToken cancellationToken, Boolean runSynchronously)

因此,我仍然被卡住了。

-----上面的问题更新----

我正在尝试调查此控制器方法的问题:

        [System.Web.Http.HttpGet]
        public IQueryable<RunOfferPublish> RunOfferPublishes()
        {
        var showIds = _showSecurityCache.GetShowIdsForCurrentUser();
        var query = Context.RunOfferPublishes.Where(rop => showIds.Contains(rop.RunOffer.Run.ShowId)).AsQueryable();
        return query;
    }

showIds数组是212个小整数(0到212)的列表。 RunOfferPublishes是DBContext(Context)

中的表

如果我删除了。在哪里查询正在运行,但它会抛出一个outof memory异常。我试图看看生成的SQL是什么,但我相信它没有达到这一点,因为我没有通过SQL Profiler看到它。

例外:

System.OutOfMemoryException: Exception of type 'System.OutOfMemoryException'  was thrown.
at System.Collections.Generic.List`1.set_Capacity(Int32 value)
at System.Collections.Generic.List`1.EnsureCapacity(Int32 min)
at System.Collections.Generic.List`1.InsertRange(Int32 index, IEnumerable`1 collection)
at System.Collections.Generic.List`1.AddRange(IEnumerable`1 collection)
at System.Data.Query.PlanCompiler.CTreeGenerator.VisitBinaryJoin(Node joinNode, DbExpressionKind joinKind)
at System.Data.Query.PlanCompiler.CTreeGenerator.Visit(LeftOuterJoinOp op, Node n)
at System.Data.Query.InternalTrees.LeftOuterJoinOp.Accept[TResultType](BasicOpVisitorOfT`1 v, Node n)
at System.Data.Query.InternalTrees.BasicOpVisitorOfT`1.VisitNode(Node n)
at System.Data.Query.PlanCompiler.CTreeGenerator.VisitAsRelOp(Node inputNode)
at System.Data.Query.PlanCompiler.CTreeGenerator.VisitJoinInput(Node joinInputNode)
at System.Data.Query.PlanCompiler.CTreeGenerator.VisitBinaryJoin(Node joinNode, DbExpressionKind joinKind)
at System.Data.Query.PlanCompiler.CTreeGenerator.Visit(LeftOuterJoinOp op, Node n)
at System.Data.Query.InternalTrees.LeftOuterJoinOp.Accept[TResultType](BasicOpVisitorOfT`1 v, Node n)
at System.Data.Query.InternalTrees.BasicOpVisitorOfT`1.VisitNode(Node n)
at System.Data.Query.PlanCompiler.CTreeGenerator.VisitAsRelOp(Node inputNode)
at System.Data.Query.PlanCompiler.CTreeGenerator.VisitJoinInput(Node joinInputNode)
at System.Data.Query.PlanCompiler.CTreeGenerator.VisitBinaryJoin(Node joinNode, DbExpressionKind joinKind)
at System.Data.Query.PlanCompiler.CTreeGenerator.Visit(LeftOuterJoinOp op, Node n)
at System.Data.Query.InternalTrees.LeftOuterJoinOp.Accept[TResultType](BasicOpVisitorOfT`1 v, Node n)
at System.Data.Query.InternalTrees.BasicOpVisitorOfT`1.VisitNode(Node n)
at System.Data.Query.PlanCompiler.CTreeGenerator.VisitAsRelOp(Node inputNode)
at System.Data.Query.PlanCompiler.CTreeGenerator.VisitJoinInput(Node joinInputNode)
at System.Data.Query.PlanCompiler.CTreeGenerator.VisitBinaryJoin(Node joinNode, DbExpressionKind joinKind)
at System.Data.Query.PlanCompiler.CTreeGenerator.Visit(LeftOuterJoinOp op, Node n)
at System.Data.Query.InternalTrees.LeftOuterJoinOp.Accept[TResultType](BasicOpVisitorOfT`1 v, Node n)
at System.Data.Query.InternalTrees.BasicOpVisitorOfT`1.VisitNode(Node n)
at System.Data.Query.PlanCompiler.CTreeGenerator.VisitAsRelOp(Node inputNode)
at System.Data.Query.PlanCompiler.CTreeGenerator.VisitJoinInput(Node joinInputNode)
at System.Data.Query.PlanCompiler.CTreeGenerator.VisitBinaryJoin(Node joinNode, DbExpressionKind joinKind)
at System.Data.Query.PlanCompiler.CTreeGenerator.Visit(LeftOuterJoinOp op, Node n)
at System.Data.Query.InternalTrees.LeftOuterJoinOp.Accept[TResultType](BasicOpVisitorOfT`1 v, Node n)
at System.Data.Query.InternalTrees.BasicOpVisitorOfT`1.VisitNode(Node n)
at System.Data.Query.PlanCompiler.CTreeGenerator.VisitAsRelOp(Node inputNode)
at System.Data.Query.PlanCompiler.CTreeGenerator.VisitJoinInput(Node joinInputNode)
at System.Data.Query.PlanCompiler.CTreeGenerator.VisitBinaryJoin(Node joinNode, DbExpressionKind joinKind)
at System.Data.Query.PlanCompiler.CTreeGenerator.Visit(LeftOuterJoinOp op, Node n)
at System.Data.Query.InternalTrees.LeftOuterJoinOp.Accept[TResultType](BasicOpVisitorOfT`1 v, Node n)
at System.Data.Query.InternalTrees.BasicOpVisitorOfT`1.VisitNode(Node n)
at System.Data.Query.PlanCompiler.CTreeGenerator.VisitAsRelOp(Node inputNode)
at System.Data.Query.PlanCompiler.CTreeGenerator.VisitJoinInput(Node joinInputNode)
at System.Data.Query.PlanCompiler.CTreeGenerator.VisitBinaryJoin(Node joinNode, DbExpressionKind joinKind)
at System.Data.Query.PlanCompiler.CTreeGenerator.Visit(LeftOuterJoinOp op, Node n)
at System.Data.Query.InternalTrees.LeftOuterJoinOp.Accept[TResultType](BasicOpVisitorOfT`1 v, Node n)
at System.Data.Query.InternalTrees.BasicOpVisitorOfT`1.VisitNode(Node n)
at System.Data.Query.PlanCompiler.CTreeGenerator.VisitAsRelOp(Node inputNode)
at System.Data.Query.PlanCompiler.CTreeGenerator.Visit(FilterOp op, Node n)
at System.Data.Query.InternalTrees.FilterOp.Accept[TResultType](BasicOpVisitorOfT`1 v, Node n)
at System.Data.Query.InternalTrees.BasicOpVisitorOfT`1.VisitNode(Node n)
at System.Data.Query.PlanCompiler.CTreeGenerator.VisitAsRelOp(Node inputNode)
at System.Data.Query.PlanCompiler.CTreeGenerator.BuildProjection(Node relOpNode, IEnumerable`1 projectionVars)
at System.Data.Query.PlanCompiler.CTreeGenerator.Visit(PhysicalProjectOp op, Node n)
at System.Data.Query.InternalTrees.PhysicalProjectOp.Accept[TResultType](BasicOpVisitorOfT`1 v, Node n)
at System.Data.Query.InternalTrees.BasicOpVisitorOfT`1.VisitNode(Node n)
at System.Data.Query.PlanCompiler.CTreeGenerator..ctor(Command itree, Node toConvert)
at System.Data.Query.PlanCompiler.ProviderCommandInfoUtils.Create(Command command, Node node, List`1 children)
at System.Data.Query.PlanCompiler.CodeGen.Process(List`1& childCommands, ColumnMap& resultColumnMap, Int32& columnCount)
at System.Data.Query.PlanCompiler.PlanCompiler.Compile(List`1& providerCommands, ColumnMap& resultColumnMap, Int32& columnCount, Set`1& entitySets)
at System.Data.EntityClient.EntityCommandDefinition..ctor(DbProviderFactory storeProviderFactory, DbCommandTree commandTree)
at System.Data.EntityClient.EntityProviderServices.CreateCommandDefinition(DbProviderFactory storeProviderFactory, DbCommandTree commandTree)
at System.Data.EntityClient.EntityProviderServices.CreateDbCommandDefinition(DbProviderManifest providerManifest, DbCommandTree commandTree)
 at System.Data.Common.DbProviderServices.CreateCommandDefinition(DbCommandTree commandTree)
 at  System.Data.Objects.Internal.ObjectQueryExecutionPlan.Prepare(ObjectContext context, DbQueryCommandTree tree, Type elementType, MergeOption mergeOption, Span span, ReadOnlyCollection`1 compiledQueryParameters, AliasGenerator aliasGenerator)
 at System.Data.Objects.ELinq.ELinqQueryState.GetExecutionPlan(Nullable`1 forMergeOption)
 at System.Data.Objects.ObjectQuery.ToTraceString()
 at System.Data.Entity.Internal.Linq.InternalQuery`1.ToString()
 at System.Data.Entity.Infrastructure.DbQuery`1.ToString()
 at ******************MainController.RunOfferPublishes() in 

3 个答案:

答案 0 :(得分:2)

这似乎是旧版EF的问题。我用EF 4.1和6.1.3尝试过这个。在4.1中,列表中只有只有3个项目(!),查询结构如下:

SELECT 
[Extent1].[AId] AS [AId], 
[Extent1].[BId] AS [BId], 
...
FROM         [dbo].[A] AS [Extent1]
INNER JOIN [dbo].[B] AS [Extent2] ON [Extent1].[BId] = [Extent2].[BId]
LEFT OUTER JOIN [dbo].[C] AS [Extent3] ON [Extent2].[CId] = [Extent3].[CId]
LEFT OUTER JOIN [dbo].[B] AS [Extent4] ON [Extent1].[BId] = [Extent4].[BId]
LEFT OUTER JOIN [dbo].[C] AS [Extent5] ON [Extent4].[CId] = [Extent5].[CId]
LEFT OUTER JOIN [dbo].[C] AS [Extent6] ON [Extent4].[CId] = [Extent6].[CId]
LEFT OUTER JOIN [dbo].[C] AS [Extent7] ON [Extent4].[CId] = [Extent7].[CId]
LEFT OUTER JOIN [dbo].[C] AS [Extent8] ON [Extent4].[CId] = [Extent8].[CId]
LEFT OUTER JOIN [dbo].[C] AS [Extent9] ON [Extent4].[CId] = [Extent9].[CId]
WHERE (1 = (CASE WHEN ([Extent3].[DId] IS NULL) THEN 0 ELSE [Extent5].[DId] END)) 
   OR (2 = (CASE WHEN ([Extent6].[DId] IS NULL) THEN 0 ELSE [Extent7].[DId] END)) 
   OR (3 = (CASE WHEN ([Extent8].[DId] IS NULL) THEN 0 ELSE [Extent9].[DId] END))

很明显,对于大量项目,要生成的联接数量会超出可用资源。

你没有告诉你使用哪个EF版本,但是如果进一步的研究发现这个查询形状是这样的,直到最近版本中的查询生成改进,我就不会感到惊讶了6.1。在6.1.3中,查询形状符合预期:

SELECT 
    [Extent1].[AId] AS [AId], 
    [Extent1].[BId] AS [BId], 
    ...
    FROM   [dbo].[A] AS [Extent1]
    INNER JOIN [dbo].[B] AS [Extent2] ON [Extent1].[BId] = [Extent2].[BId]
    INNER JOIN [dbo].[C] AS [Extent3] ON [Extent2].[CId] = [Extent3].[CId]
    WHERE (CASE WHEN ([Extent3].[DId] IS NULL) THEN 0 
    ELSE [Extent3].[DId] END IN (1, 2, 3)) 
    AND (CASE WHEN ([Extent3].[DId] IS NULL) THEN 0 ELSE [Extent3].[DId] END IS NOT NULL)

context.Configuration.UseDatabaseNullSemantics = true;更加苗条:

WHERE CASE WHEN ([Extent3].[DId] IS NULL) THEN 0 ELSE [Extent3].[DId] END IN (1, 2, 3)

因此,您可以使用您设法找到的解决方法,或升级到以后的EF版本。

答案 1 :(得分:0)

EF and Contains often don't play well together. Mabe it's possible to rewrite the query without the contains. I'm guessing at your DB schema, but maybe something along these lines:

var userId = _showSecurityCache.GetIdForCurrentUser();
var query = Context.RunOfferPublishes.Where(rop => Context.Users.Any(u => u.Id == userId && u.Shows.Any(s => s.Id == rop.RunOffer.Run.ShowId))).AsQueryable();
return query;

答案 2 :(得分:0)

以这种方式进行连接,解决了问题。这就像你必须告诉EF确切地生成什么SQL,否则它会崩溃。

    [System.Web.Http.HttpGet]
    public IQueryable<RunOfferPublish> RunOfferPublishes()
    {
        var showIds = _showSecurityCache.GetShowIdsForCurrentUser();
        return (from rop in Context.RunOfferPublishes
                   join ro in Context.RunOffers on rop.RunOfferId equals ro.RunOfferId
                   join r in Context.Runs on ro.RunId equals r.RunId
                   where showIds.Contains(r.ShowId)
                   select rop);
    }