实体框架+ ODATA:侧面踩踏

时间:2012-07-24 17:47:08

标签: entity-framework pagination odata

我正在开发的项目在OData层之上有实体框架。 Odata层使其服务器端分页变为值75。我对这个主题的阅读使我相信这个分页值是全面使用的,而不是每个表格。我当前希望从中提取所有数据的表格当然超过75行。使用实体框架,我的代码就是这样:

public IQueryable<ProductColor> GetProductColors()
{
   return db.ProductColors;
}

其中db是实体上下文。这将返回前75条记录。我读了一些内容,我可以将参数inlinecount设置为allpages,并为我提供以下代码:

public IQueryable<ProductColor> GetProductColors()
{
   return db.ProductColors.AddQueryOption("inlinecount","allpages");
}

然而,这也会返回75行!

任何人都可以了解如何真正获取所有记录,而不管OData服务器端的分页内容是什么?

重要:我无法删除分页或将其关闭!在性能受到关注的其他场景中,它非常有价值。

更新 通过更多搜索,我找到了一个描述如何完成此任务的MSDN

我希望能够将它变成一个完整的Generic方法,但是,这与我可以在不使用反射的情况下获得通用一样接近:

public IQueryable<T> TakeAll<T>(QueryOperationResponse<T> qor)
    {
      var collection = new List<T>();
      DataServiceQueryContinuation<T> next = null;
      QueryOperationResponse<T> response = qor;
      do
      {
        if (next != null)
        {
          response = db.Execute<T>(next) as QueryOperationResponse<T>;
        }

        foreach (var elem in response)
        {
          collection.Add(elem);          
        }

      } while ((next = response.GetContinuation()) != null);

      return collection.AsQueryable();
    }

称之为:

public IQueryable<ProductColor> GetProductColors()
    {      
      QueryOperationResponse<ProductColor> response = db.ProductColors.Execute() as QueryOperationResponse<ProductColor>;
      var productColors = this.TakeAll<ProductColor>(response);
      return productColors.AsQueryable();
    }

2 个答案:

答案 0 :(得分:5)

如果无法关闭分页,您将始终获得75行待命。您可以通过以下方式获取所有行:

  1. 添加另一个IQueryable<ProductColor> AllProductColors并修改

    public static void InitializeService(DataServiceConfiguration config)
    {
        config.UseVerboseErrors = true;
        config.SetEntitySetAccessRule("*", EntitySetRights.AllRead);
        config.SetEntitySetPageSize("ProductColors", 75); - Note only paged queries are present
        config.SetServiceOperationAccessRule("*", ServiceOperationRights.AllRead);
        config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
    }
    
  2. 您应该根据需要调用ProductColors,例如

        var cat = new NetflixCatalog(new Uri("http://odata.netflix.com/v1/Catalog/"));
    
        var x = from t in cat.Titles
                where t.ReleaseYear == 2009
                select t;
        var response = (QueryOperationResponse<Title>)((DataServiceQuery<Title>)x).Execute();
    
        while (true)
        {
            foreach (Title title in response)
            {
                Console.WriteLine(title.Name);
            }
    
            var continuation = response.GetContinuation();
            if (continuation == null)
            {
                break;
            }
    
            response = cat.Execute(continuation);
        }
    
  3. 我使用Rx和以下代码

    public sealed class DataSequence<TEntry> : IObservable<TEntry>
    {
        private readonly DataServiceContext context;
        private readonly Logger logger = LogManager.GetCurrentClassLogger();
        private readonly IQueryable<TEntry> query;
    
        public DataSequence(IQueryable<TEntry> query, DataServiceContext context)
        {
            this.query = query;
            this.context = context;
        }
    
        public IDisposable Subscribe(IObserver<TEntry> observer)
        {
            QueryOperationResponse<TEntry> response;
            try
            {
                response = (QueryOperationResponse<TEntry>)((DataServiceQuery<TEntry>)query).Execute();
                if (response == null)
                {
                    return Disposable.Empty;
                }
            }
            catch (Exception ex)
            {
                logger.Error(ex);
                return Disposable.Empty;
            }
            var initialState = new State
                                   {
                                       CanContinue = true,
                                       Response = response
                                   };
            IObservable<TEntry> sequence = Observable.Generate(
                initialState,
                state => state.CanContinue,
                MoveToNextState,
                GetCurrentValue,
                Scheduler.ThreadPool).Merge();
            return new CompositeDisposable(initialState, sequence.Subscribe(observer));
        }
    
        private static IObservable<TEntry> GetCurrentValue(State state)
        {
            if (state.Response == null)
            {
                return Observable.Empty<TEntry>();
            }
            return state.Response.ToObservable();
        }
    
        private State MoveToNextState(State state)
        {
            DataServiceQueryContinuation<TEntry> continuation = state.Response.GetContinuation();
            if (continuation == null)
            {
                state.CanContinue = false;
                return state;
            }
            QueryOperationResponse<TEntry> response;
            try
            {
                response = context.Execute(continuation);
            }
            catch (Exception)
            {
                state.CanContinue = false;
                return state;
            }
            state.Response = response;
            return state;
        }
    
        private sealed class State : IDisposable
        {
    
            public bool CanContinue { get; set; }
    
            public QueryOperationResponse<TEntry> Response { get; set; }
    
            public void Dispose()
            {
                CanContinue = false;
            }
        }
    }
    

    因此,要通过OData获取任何数据,请创建一个序列,Rx执行其余的

     var sequence = new DataSequence<Product>(context.Products, context);
     sequence.OnErrorResumeNext(Observable.Empty<Product>())
                .ObserveOnDispatcher().SubscribeOn(Scheduler.NewThread).Subscribe(AddProduct, logger.Error);
    

答案 1 :(得分:2)

页面大小由服务作者设置,可以按实体集设置(但服务可以选择将相同的页面大小应用于所有实体集)。没有办法从客户端避免它(这是设计,因为它是一个安全功能)。

inlinecount选项要求服务器包含结果的总计数(只是数字),它不会禁用分页。

从客户端读取所有数据的唯一方法是发出将返回第一页的请求,它可能包含您请求读取下一页的下一个链接,依此类推,直到最后一个响应没有有下一个链接。

如果您正在使用WCF数据服务客户端库,它支持延续(下一个链接),可以在此博客文章中找到一个简单的示例(例如):http://blogs.msdn.com/b/phaniraj/archive/2010/04/25/server-driven-paging-with-wcf-data-services.aspx