2012-07-24 36 views
2

我工作的项目有实体框架上的OData层的顶部。 Odata图层将其服务器端分页转换为值为75。我对这个主题的阅读使我相信,这个分页值是全面使用的,而不是每个表的基础。我目前希望从提取所有数据表,当然,超过75行。使用实体框架,我的代码只是这样的:实体框架+ ODATA:侧步执行分页

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

其中db是实体环境。这是返回前75个记录。我读的东西在那里我可以一个参数inlinecount集追加到allpages给我下面的代码:

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

然而,这也将返回75行!

谁能阐明了如何真正得到所有的记录,而不管的的OData服务器端分页的东西?

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

更新: 通过一些搜索我发现一个MSDN描述如何执行此任务。

我很想能够把它变成一个完整的通用方法,但是,这是亲如我能得到一个通用的,而无需使用反射:

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(); 
    } 

回答

7

如果无法关闭分页,你总是会收到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); 
        } 
    

我用以下代码使用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); 
2

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

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

从客户端读取所有数据的唯一方法是发出请求,它将返回第一个页面,并且它可能包含您请求读取下一个页面的下一个链接等等,直到最后一个响应结束为止,没有下一个链接。

如果你使用它有延续(下一个环节)和一个简单的示例支持WCF数据服务客户端库可以在这个博客帖子(例如)中找到:http://blogs.msdn.com/b/phaniraj/archive/2010/04/25/server-driven-paging-with-wcf-data-services.aspx