我正在开发的项目在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();
}
答案 0 :(得分:5)
如果无法关闭分页,您将始终获得75行待命。您可以通过以下方式获取所有行:
添加另一个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;
}
您应该根据需要调用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);
答案 1 :(得分:2)
页面大小由服务作者设置,可以按实体集设置(但服务可以选择将相同的页面大小应用于所有实体集)。没有办法从客户端避免它(这是设计,因为它是一个安全功能)。
inlinecount选项要求服务器包含结果的总计数(只是数字),它不会禁用分页。
从客户端读取所有数据的唯一方法是发出将返回第一页的请求,它可能包含您请求读取下一页的下一个链接,依此类推,直到最后一个响应没有有下一个链接。
如果您正在使用WCF数据服务客户端库,它支持延续(下一个链接),可以在此博客文章中找到一个简单的示例(例如):http://blogs.msdn.com/b/phaniraj/archive/2010/04/25/server-driven-paging-with-wcf-data-services.aspx