1

我在使用 EF4.1 时遇到了一些内存问题,问题主要发生在这种情况下:假设我有学生,可以参加一门或多门课程,并且多个用户可以参加同一门课程。所以,我有类似的东西:

Student * < - > 1-* Course

想象一下,我的 BD 中有 2 名学生和 1 门课程。像这样:

安娜参加英语课程 鲍勃参加英语课程

我的对象图是这样的:

Ana  
    \
      English Course
    /
Bob

这可以。

我保存了这个,那个保存得很好,学生表上有两行,课程表上有一行。

问题是当我尝试获取这些数据时。

当我做类似的事情时:

 var students = (from s in students
                 select s).Include("Courses");

这是结果图:

 Ana -> English Course
 Bob -> English Course

对象被复制。想象一下,当这棵树的深度更大时,有数千名学生和数千门课程,以及数百名学生参加同一门课程。

这个查询的内存使用会很大,如何解决这个引用问题?

4

2 回答 2

0

您的价值不会重复,因为如果您只有

Ana -> English Course

你将无法了解 Bob 正在学习什么。如果您只对不同的课程感兴趣,您可以使用 distinct 关键字,也可以按课程分组。因此,如果您只需要课程的不同值,那么您没有参考问题,您只是生成了错误的查询。如果你能准确地告诉我你想达到什么目标,我可能会为你提供更多信息。

于 2011-10-31T21:19:28.817 回答
0

如果您AsNoTracking在查询中使用,则对象不会加载到上下文中并且不会缓存在那里。但是如果没有上下文,您就没有身份映射,这意味着:您没有键属性值和对象引用身份之间的唯一映射。因此,EF 将为每个加载的导航属性创建一个新对象,因此您将获得同一个键的多个对象。这使得加载速度更快,因为不需要创建身份映射,也不需要用于更改跟踪的属性快照,但它可能会消耗更多内存。

据我所知,如果不将数据加载到上下文中,就无法避免对象实现过程中的对象重复。

为了在不 加载数据时提高性能,AsNoTracking您可以尝试从急切加载课程集合转移到显式加载。众所周知,急切加载会导致数据库和客户端之间传输的数据大量增加,这会对性能产生非常负面的影响。使用显式加载您的代码将如下所示:

// no Include and no AsNoTracking here
var students = (from s in context.Students select s).ToList();
foreach (var student in students)
{
    context.Entry(student).Collection(s => s.Courses).Load();
}

student这会为每个加载的Courses集合创建一个额外的数据库查询。关于性能,这样做听起来很疯狂,但有一些例子表明,这仍然比使用预加载的单个查询快得多(如本例所示:检测具有相同子级的实体(请参阅对此答案的评论:167 中的性能增益)从急切加载到显式加载后,秒到 3.4 秒))。

不应在此处复制对象,因为它们已具体化到上下文中。

于 2011-11-02T15:40:59.790 回答