【问题标题】:Can I improve WCF OData Expand queries我可以改进 WCF OData 扩展查询吗
【发布时间】:2014-12-17 10:11:37
【问题描述】:

我在 Entity Framework 6 DbContext 之上有一个 WCF DataService (v3)。

我有以下表格

  • 订单
  • 付款方式
  • 交付方法

订单表有大约 300000 条记录。现在我想查询数据。用EF我会做的

using (var context = new OrderContext())
{
    var query = context.Orders
        .Include("PaymentMethod")
        .Include("DeliveryMethod");

    var items = query.Take(100).ToList();
}

此代码在 1 秒内执行。这很好。

现在有了 DataService:

var context = new OrderContext(uri);
var query = context.CreateQuery<Order>()
    .Expand("PaymentMethod,DeliveryMethod")
var items = query.Take(100).ToList();

这需要 10 秒。如果我跳过Expand(),它只需要 1 秒。也。所以基本上,扩展似乎大大减慢了查询的执行速度,并且每增加一个包含就变得更糟。看起来它与对象计数并没有真正的关系(如果我将页面大小更改为 10 甚至 1000),则减少/增加可以忽略不计。

知道如何解决这个问题吗?

更新

这是我的 DataService 类

public class OrderDataService : EntityFrameworkDataService<OrderContext>
{
    protected override OrderContext CreateDataSource()
    {
        return new OrderContext();
    }

    public static void InitializeService(DataServiceConfiguration config)
    {
        config.SetEntitySetAccessRule("*", EntitySetRights.All);

        config.SetServiceOperationAccessRule("*", ServiceOperationRights.All);

        config.SetServiceActionAccessRule("*", ServiceActionRights.Invoke);

        config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3;

        config.UseVerboseErrors = true;
    }
} 

更新 2

我使用以下来自 nuget 的库

  • EntityFramework 6.1.1
  • Microsoft.Data.OData 5.6.3(也是 Microsoft.Data.Services...)
  • Microsoft.OData.EntityFrameworkProvider 1.0.0-beta2

【问题讨论】:

  • 您的代码没有显示您如何公开您的IQueryable,它很可能依赖延迟加载来实现您的扩展(如果使用的 OData 提供程序不支持 EF(例如反射 OData 提供程序))。这一点很重要,因为有大约 5 种不同风格的 Wcf 数据服务(Web-API WCF DS、WCF DS RIA 和 OData,仅举几例)。
  • 我正在使用EntityFrameworkDataService
  • 是的……那是破旧的技术。您实际上是在使用反射 OData 提供程序,因为该类不支持 DbContext。有一个愚蠢的解决方法,我回家后会发布。
  • 那太棒了。我刚从EF5 + ReflectionProvider 移动到EF6 + EntityFrameworkProvider,但我也从一个有几条记录的开发数据库转移到了生产环境,所以我不知道这个问题是否是由 EF6 引起的

标签: c# entity-framework wcf wcf-data-services


【解决方案1】:

试试这个

public class OrderDataService : EntityFrameworkDataService<ObjectContext>
{
    protected override ObjectContext CreateDataSource()
    {
        IObjectContextAdapter context = new OrderContext();
        return context.ObjectContext;
    }
} 

【讨论】:

  • 抱歉,看起来很有希望,但没有帮助 :-( - 与此同时,我已经为 WebApi 2.2 创建了一个 OData4 端点 - 速度稍快,但我想是出于其他原因。基本问题,扩展速度变慢查询,仍然存在。
【解决方案2】:

好的,这会导致头部有些疼痛,但我找到了原因。

我怀疑 OData Expand 是问题所在,因为包含包含的实体框架表现得更好,但这只是因为 OData 隐式添加了一个 ORDER BY ID 到我的查询中。事实证明,当前的 MySQL Connector for NET 为 Include with OrderBy 生成了糟糕的 sql。

基本上就是这个查询

var query = context.Orders
    .Include(x => x.Paymentmethods)
    .OrderBy(x => x.Id)
    .Take(10);

生成这样的查询

SELECT
`Project1`.`C1`, 
`Project1`.`id`, 
`Project1`.`name`, 
`Project1`.`paymentmethod_id`, 
`Project1`.`id1`, 
`Project1`.`name1`
FROM (SELECT
`Extent1`.`id`, 
`Extent1`.`name`, 
`Extent1`.`paymentmethod_id`, 
`Extent2`.`id` AS `id1`, 
`Extent2`.`name` AS `name1`, 
1 AS `C1`
FROM `orders` AS `Extent1`
    INNER JOIN `paymentmethods` AS `Extent2` ON
        `Extent1`.`paymentmethod_id` = `Extent2`.`id`) AS `Project1`
 ORDER BY 
`Project1`.`id` ASC LIMIT 10

它查询所有行以使用文件排序对临时表进行排序。对于 Sql Server,查询将很简单

SELECT TOP (10) 
[Extent1].[id] AS [id], 
[Extent1].[name] AS [name], 
[Extent1].[paymentmethod_id] AS [paymentmethod_id], 
[Extent2].[id] AS [id1], 
[Extent2].[name] AS [name1], 
FROM  [orders] AS [Extent1]
LEFT OUTER JOIN [paymentmethods] AS [Extent2] ON [Extent1].[paymentmethod_id] = [Extent2].[id]
ORDER BY [Extent1].[id] ASC

效果更好

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多