Entity Framework 3.5 - 如何加载子项

10

我的问题可能非常简单,如何加载子类。我找不到任何"load"或类似的东西来让上下文加载子类。

上下文类是ObjectContext类型,如下所示:

public partial class RTIPricingEntities : global::System.Data.Objects.ObjectContext
 

产品

 

Product.ModifiedByUser(如何在加载产品时加载此类?)

 

Product.Category(如何在加载产品时加载类别?)


这是我加载数据的示例:也许我应该提到,我正在为Silverlight应用程序编写代码。而且这是通过域服务实现的。 RTIPricingContext _context = new RTIPricingContext(); LoadOperation<PurchaseOrder> op = _context.Load(context.GetPurchaseOrderQuery(), PurchaseOrdersLoadedCallback, null); private void PurchaseOrdersLoadedCallback(LoadOperation<PurchaseOrder> lo) { IEnumerable<PurchaseOrder> po = lo.Entities.Where(w => w.UserID == SelectedUser.ID); // 这是我需要填充子类的集合。 - Jukeman
4个回答

16

你可以使用急切加载:

var q = from p in Context.Products
                  .Include("ModifiedByUser")
                  .Include("Category")
        select p;

...或项目:

var q = from p in Context.Products
        select new 
        {
           Id = p.Id,
           Name = p.Name
           ModifiedByUserName = p.ModifiedByUser.Name,
           CategoryName = p.Category.Name
        }
投影的优点在于您只获取所需数据,而不是每个引用实体的整个内容。急切加载的优点在于返回的实体具有更改跟踪。根据手头问题选择正确的技术。 更新 是的,提到您正在使用RIA服务很重要。我假设您也在客户端工作。这使事情完全不同。 在RIA服务中,非常重要的是确保在初始加载时返回您需要的整个实体关系图。您不想在实体上调用类似.Load()的任何方法,因为这将是对服务器的另一个热点访问,这对性能来说是不好的。如果您在例如Silverlight客户端中请求服务器上的实例列表,并且其相关属性尚未被材料化,那么现在已经太迟了。此外,在Silverlight客户端中不起作用。因此,RIA服务有可用于确保最初返回正确的、完全材料化对象图的服务器端工具。 您需要做的是在RIA服务服务器中使用IncludeAttribute。您可以创建一个“伙伴”元数据类来装饰您的实体模型,其中包含[Include]。在RIA服务概述文档第4.8节中有示例。

你好,我不知道我们是否使用的是同一个版本,但在我的编码中两个选项都不可行。没有“.Include”可用,只有“Intersect”.. 我正在使用以“ObjectContext”为基类的entityframework派生实体。当我进行投影时,智能感知中没有属性可以设置。 - Jukeman
1
Include是ObjectQuery<T>的一个方法,而不是IQueryable<T>的方法。因此,请检查您所拥有的引用类型。实体不是从ObjectContext派生的,而是从EntityObject派生的。在我的示例中,投影对象上不会有任何IntelliSense,因为我使用了匿名类型。如果我使用非匿名类型,则会有IntelliSense。 - Craig Stuntz

8
使用像其他人建议的.Include()是实现所需功能的好方法。
然而,有时您可能需要稍后“重新加载”某些未被“包含”的内容,或者仅在某些情况下需要它们,因此在许多情况下放置一个Include语句可能会浪费计算周期。
在像“Product.Category”这样的单一关系中(其中Product.Category是从产品到类别的导航属性),您很可能也有一个“Product.CategoryReference”元素。 您可以检查它是否已加载,如果没有,则可以“按需”加载它:
if(!Product.CategoryReference.IsLoaded)
{
    Product.CategoryReference.Load();
}

现在你所引用的“类别”应该已经被加载到内存中并可以直接使用。
如果你有一个导航属性,它引用了一组东西(例如产品的“部件”),你也可以直接在导航属性上执行同样的操作:
if(!Product.Parts.IsLoaded)
{
    Product.Parts.Load();
}

这可以是一种有用的技术,用于在您未将单个或集合类型的导航属性“包含”到EF查询中时进行“按需加载”。
Marc

谢谢大家,我意识到我无法实现许多提出的解决方案的原因是因为一旦由域服务转换为Silverlight,上下文就不同了。在实体框架数据模型的代码后台中,我可以实现你们所有的解决方案,我刚刚发现了这一点。但感谢你们的帮助,我知道问题肯定是我在找错地方... - Jukeman

3
您可以使用 Include() 方法来指定查询结果中包含的相关对象,而且可以链接多个 Include() 方法以加载多个相关对象。这个方法属于 System.Data.Objects.ObjectQuery

例如,要加载 ModifiedByUser 和 Category,您可以使用以下查询:

var q = from p in context.Products.Include("ModifiedByUser").Include("Category") 
        select p;

如果您的Category实体还有一个ModifiedByUser实体需要加载,您可以使用以下查询语句:

如果您的Category实体还有一个ModifiedByUser实体需要加载,您可以使用以下查询语句:

var q = from p in context.Products
              .Include("ModifiedByUser")
              .Include("Category.ModifiedByUser") 
        select p;

请参考MSDN上的调整查询结果,了解更多示例。


我经常看到这个解决方案,所以我一定和其他人做的完全不同。基本上,我是使用由entityframework生成的datamodel中的上下文。我拥有最新的.Net。没有“Include”可用。你在这个例子中使用dbml/linq吗?我想这就是为什么不同的原因... - Jukeman

0

我注意到Craig提出的解决方案没有同时加载ModifiedByUser和Category。它只加载了最后一个对象集合,即“Category”。

var q = from p in Context.Products
              .Include("ModifiedByUser")
              .Include("Category")
    select p;

然而,如果你调换顺序,让它变成 .Include("Category").Include("ModifiedByUser"),那么就会加载ModifiedByUser。奇怪的是,这两个对象集合的IsLoaded属性都会显示“true”,但是第一个对象集合的计数始终为零。不确定为什么会这样。

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