【问题标题】:Is it possible to lazy load complex types from a WCF Data Service是否可以从 WCF 数据服务延迟加载复杂类型
【发布时间】:2013-09-25 11:43:10
【问题描述】:

我有 DbContext 子类

ReportingContext : DbContext

当我在做简单的 CRUD 时,我创建了一个 WCF 数据服务来公开我的 DbSet...

public class ReportService : DataService<ReportingContext>

我已经能够直接使用 ReportingContext 来进行“表格拆分”。基本上使用 2 个实体(ReportLayout 和 ReportLayoutData),它们都使用一个表。我能够使用 fluent API 进行配置。在单元测试中一切正常,因为我能够返回 ReportLayouts 并且仅在访问它们时加载 ReportLayoutData。

当我尝试通过 WCF 数据服务 OData 版本 5.6 执行此操作时,我的问题开始了 - 使用 DataServiceContext 类。返回 ReportLayouts 工作正常,但目前还无法尝试延迟加载相关数据。我尝试了不同的方法:

  • 当我直接调试服务并检查生成的 sql - 2 个单独的查询作为单元测试时,通过服务方法调用 Include 确实有效。但是,在浏览器中查看时,该服务根本没有在其返回的属性中包含 ReportLayoutData 属性,并且我收到了与缺少属性有关的客户端错误。

    [WebGet]
    public IQueryable<ReportLayout> GetReportsByID(string ids)
    {
        var ints = GetInts(ids);
        return  CurrentDataSource.Reports.Include("LayoutData").Where(x =>  ints.Contains(x.ReportLayoutID)).AsQueryable();
    }
    
    private static int[] GetInts(string ids)
    {
        return ids.Split(",".ToCharArray()).Select(x => Convert.ToInt32(x)).ToArray();
    }
    
  • 我尝试使用 DataServiceContext.Expand - $expand - 但失败了 错误,因为我尝试了稍微不同的论点

  • 我尝试调用Execute,各种问题

  • 我将 ReportLayoutData 属性转换为 IQueryable,即使它是 1-1 关系,现在它说在运行以前运行良好的 EF 特定单元测试时 ReportLayoutData 不是 ReportLayout 的属性。

我的问题:是否可以通过 WCF 数据服务以这种方式进行延迟加载,或者我应该只公开 2 个集合并将结果解析为客户端上的单个对象?如果可能的话,我只想看看基本模式——几个相关的实体、流畅的 API 声明和 DataService 代码。感谢您的帮助。

编辑

我目前正被错误困扰:

类型为“ReportLayout”的名为“LayoutData”的属性具有“结构”类型,但应为“导航”类型。

虽然在浏览器中检索数据没有问题:ReportService.svc/Reports()?$expand=LayoutData

部分堆栈跟踪:

Microsoft.Data.OData.ReaderValidationUtils.ValidateNavigationPropertyDefined(String propertyName, IEdmEntityType owningEntityType, ODataMessageReaderSettings messageReaderSettings) 在 Microsoft.Data.OData.Atom.ODataAtomEntryAndFeedDeserializer.TryReadNavigationLinkInEntry(IODataAtomReaderEntryState entryState, String linkRelation, String linkHRef)

我能够通过不通过服务公开 2 个 dbSet 来消除上述错误。会考虑使用服务操作从 EF 返回我需要的东西,可惜它不是那么优雅。

【问题讨论】:

  • 首先,没有现成的实现延迟加载的方法。这当然是可能的。但是,我强烈反对它。使用 OData 的往返行程通常约为几百毫秒。延迟加载本质上是一种同步模式。在典型的应用程序中,用户会注意到几百毫秒的无响应。如果我们是紧密循环,请完全忘记 UX。您可以查看DataServiceContext.LoadProperty,但我建议您尽可能使用异步调用。
  • @Aron 谢谢你 - 我确实尝试过 LoadProperty,如果我没记错的话,它给了我一条错误消息,说它只适用于集合。我当时的 ReportLayout 当时只公开了一个 virtual ReportLayoutData 对象。我可以再试一次,如果只是为了看到它工作的满足感。我认为您对 UX 的看法是正确的,但没有看到问题,因为它只是一个请求,并且此调用可以异步进行。
  • @Aron 真痛苦,如果我将 ReportLayout.LayoutData 设为集合,我在尝试实例化服务时会收到缺少属性异常。如果我尝试将 LoadProperty 与仅具有单个对象属性的 ReportLayout 一起使用,我会得到 - 封闭类型 Framework.Reports.ReportLayout 没有相应的 ReportLayout/LayoutData 可设置属性。我以前遇到过这个错误,我想是时候喝杯咖啡了,忘记通过 WCF 进行延迟加载。
  • 嗯...Report.LayoutData 上是否有 set
  • @Aron Yes - public virtual ReportLayoutData LayoutData { get;放; }

标签: c# .net wcf entity-framework entity-framework-5


【解决方案1】:

最后我的解决方案是拆分表格,以便创建一个作为 ICollection 公开的导航属性

结果,我能够实现诸如 Reports/ReportService.svc/Reports(1) $expand=LayoutData 之类的查询 (AddQueryOption("$expand", "LayoutData") 并写了一个服务方法为多个执行此操作。

    [WebGet]
    public IQueryable<ReportLayout> GetReportsByID(string ids)

我只通过服务公开了一个 Dbset - 无法直接访问子级。

可以使用 DataServiceContext 方法实现对依赖实体的客户端更新:

AddObject, AddLink
AttachTo, UpdateObject, AttachLink //UpdateObject on the child ensures the entity state changes to modified (see DataServiceContext.Entites collection).

回想起来,我可能不需要拆分桌子,但没有时间玩这个。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-07-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多