我有这样的代码:
var myList = db.Table1.ToList();
/*doing some operations on the list*/
var myList = db.Table2.ToList();
/*again doing some operations on the list*/
var myList = db.Table3.ToList(); // I'm getting out of memory exception here.
我无法按页检索数据,因为我需要一次所有表。在加载另一个表之前,如何处理(我的意思是释放该列表所公开的空间)列表?感谢。
编辑:
我加载后,实际上是从myList生成了很多(有时是数千个)子列表。所以我真的需要学习如何释放列表。
编辑2: 这是我的完整Stacktrace:
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.Add(T item)
at System.Data.Entity.Core.Objects.EntityEntry.TakeSnapshot(Boolean onlySnapshotComplexProperties)
at System.Data.Entity.Core.Objects.Internal.SnapshotChangeTrackingStrategy.TakeSnapshot(EntityEntry entry)
at System.Data.Entity.Core.Objects.Internal.EntityWrapper`1.TakeSnapshot(EntityEntry entry)
at System.Data.Entity.Core.Objects.ObjectStateManager.AddEntry(IEntityWrapper wrappedObject, EntityKey passedKey, EntitySet entitySet, String argumentName, Boolean isAdded)
at System.Data.Entity.Core.Common.Internal.Materialization.Shaper.HandleEntityAppendOnly[TEntity](Func`2 constructEntityDelegate, EntityKey entityKey, EntitySet entitySet)
at System.Data.Entity.Core.Common.Internal.Materialization.Coordinator`1.ReadNextElement(Shaper shaper)
at System.Data.Entity.Core.Common.Internal.Materialization.Shaper`1.SimpleEnumerator.MoveNext()
at System.Data.Entity.Internal.LazyEnumerator`1.MoveNext()
at System.Collections.Generic.List`1.InsertRange(Int32 index, IEnumerable`1 collection)
at System.Collections.Generic.List`1.AddRange(IEnumerable`1 collection)
at WebApplication2.MyMethod in line 2292
at WebApplication2.Controllers.MyController.MyActtion(String myString) in line 137
at System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters)
at System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters)
at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters)
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<BeginInvokeSynchronousActionMethod>b__39(IAsyncResult asyncResult, ActionInvocation innerInvokeState)
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`2.CallEndDelegate(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.End()
at System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethod(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3d()
at System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.<>c__DisplayClass46.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3f()
答案 0 :(得分:5)
根据帖子评论中的其他说明,db
是3个调用之间的EF DbContext
派生类变量,共享。 Table1
,Table2
和Table3
是该上下文中的DbSet
个实例。
使用var myList = db.Table1.ToList()
时会发生的情况是,除了在内存中读取表格并填写列表之外,EF DbContext
还会使用相同的对象填充内部DbSet.Local
集合(所谓的 tracking ),以便能够检测并应用您(最终)对底层对象所做的更改。
这就是问题所在。如果您Clear
设置为null
myList
变量,内部缓存(列表)仍保留所有这些对象,最终会在某个时刻导致OutOfMemoryException
,则会发生事件。
因此,如果您不打算修改返回的对象并将它们保存回数据库,那么通过使用所谓的No-Tracking Queries来完全消除DbContext
内部缓存:
var myList = db.Table1.AsNoTracking().ToList();
或清理(Dispose
并设置为null
)并为每个列表流程使用全新的上下文(db = new YourDbContext()
)。
当然,您可以将上述内容与评论中提到的其他技术结合起来,以清理您自己的列表变量。
答案 1 :(得分:0)
根据我上面的评论,ToList
在处理大量项目时会对内存造成严重影响。
因此,通过预先分配List,有时可以获得更好的内存性能。
所以:
var tableCount = db.Table1.Count();
var myList = new List<Table1Item>(tableCount); //I don't know the type parameter here
myList.AddRange(db.Table1); //or db.Table1.AsEnumerable() ?