2012-07-24 35 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