寻找Entity Framework上下文对象

13

通过在这里和其他论坛上提出的各种问题,我得出结论,在使用Entity Framework中生成的实体上下文对象时,我完全不知道自己在做什么。

背景是,我有大量使用LLBLGen Pro的经验,而Entity Framework对我来说只有三周的时间。

假设我有一个名为“myContext”的上下文。我的模型中有一个名为Employee的表/实体,因此现在我有一个myContext.Employees。我认为这意味着该属性表示上下文中的Employee实体集。但是,我错了,因为我可以使用以下代码向上下文添加新实体:

myContext.Employees.AddObject(new Employee());

从我的理解来看,这个新的Employee实体在myContext.Employees中根本没有出现。我了解到,找到这个新添加的实体的唯一方法是在myContext.ObjectStateManager中追踪它。这对我来说听起来像是myContext.Employees集合实际上不是上下文中存在的Employee实体的集合,而是某种表示存在于数据库中的Employee实体的方式。

更进一步地,假设我正在查看一个单独的Employee实体。有一个Project实体,它与Employee具有M:1关系(一个员工可以拥有多个项目)。如果我想要给特定的员工添加一个新项目,我只需要执行:

myEmployee.Projects.Add(new Project());

太好了,这实际上按照我的期望将项目添加到了集合中。但是这与上下文的ObjectSet属性的工作方式完全不同。如果我使用以下方式向上下文添加新项目:

myContext.Projects.AddObject(new Project());

这不会改变项目集合。

如果有人能够解释一下,我将非常感激。此外,我真的想要一个包含上下文中所有员工(或项目)的集合,并且我希望它作为上下文的属性可用。在EF中是否可能实现?

1个回答

16

ObjectSet是一个查询,就像LINQ中的所有内容一样,它是惰性的。在枚举或调用.Count()等方法之前,它不会执行任何操作。此时会运行一个数据库查询,并将返回的任何实体与已经存在于上下文中的实体合并。

因此,您可以执行以下操作:

var activeEmployees = Context.Employees.Where(e => e.IsActive)

... 不运行查询的情况下。

你可以进一步组合这个:

var orderedEmployees = activeEmployees.OrderBy(e => e.Name);

...再次执行查询的情况下。

但是,如果您查看该集合:

var first = orderedEmployees.First();

然后运行数据库查询。这对所有的LINQ都是共同的。

如果你想枚举已经在上下文中存在的实体,你需要转向ObjectStateManager。所以对于Employees,你可以做到:

var states = EntityState.Added || EntityState.Deleted || // whatever you need
var emps = Context.ObjectStateManager.GetObjectStateEntries(states)
                                     .Select(e => e.Entity)
                                     .OfType<Employee>();

请注意,尽管这样可以工作,但这不是我建议使用的方式。通常,您不希望您的ObjectContext具有长寿命。由于这个原因和其他原因,它们并不适合作为对象的通用容器。使用通常的List类型。更准确地说,将ObjectContext视为工作单元。通常,在工作单元中,您已经知道要使用哪些实例。


ObjectContext 去做更改跟踪。但如果你需要一个活动员工列表,而且不想每次都查询数据库,尽管使用 List 或类似的东西。只要意识到,如果列表超出上下文的生命周期,你必须先分离和附加才能在更新中使用实体,所以通常重新查询会更容易(而且足够快)。缓存策略很难得到正确的结果。 - Craig Stuntz
对的,List 需要和 ObjectContext 同步。所以从 List 中添加/删除会导致将其添加/删除到 ObjectContext 中,反之亦然。天啊,这真是一件烦心事...希望微软内置了这样的功能。 - Mike Gates
如果你真的这样做了,那么你有更大的问题。重新考虑ObjectContext,使得你不会在显示和更新时使用相同的上下文。再次将其视为工作单元。 - Craig Stuntz
4
使用MVC或MVVM模式。随着用户通过屏幕,逐步构建编辑模型,然后在单个更新操作中提交所有内容。上下文只在更新期间持续存在,因为那是你的工作单位。其他工作单位是填充每个屏幕。 - Craig Stuntz
如果读者想象一个派生自DbContext的上下文和一个DbSet<Employees>,这个问题和答案的阅读可能会有些困惑。随着Entity Framework的后续更新,行为就像问答者所期望的那样。调用context.Employees.Add(new Employee())确实会在Employees DbSet上使该新员工可用。 - Josh Gallagher
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接