如何在 OData 服务下使用字典或哈希表来提高 LINQ 查询性能
我对 OData 很陌生(昨天才开始),所以如果这个问题太愚蠢,请原谅我:-)
我已经构建了一个测试项目作为概念验证,用于将我们当前的 Web 服务迁移到 OData。对于此测试项目,我使用 Reflection Providers 通过 OData 公开 POCO 类。这些 POCO 类来自内存缓存。下面是到目前为止的代码:
public class DataSource
{
public IQueryable<Category> CategoryList
{
get
{
List<Category> categoryList = GetCategoryListFromCache();
return categoryList.AsQueryable();
}
}
// below method is only required to allow navigation
// from Category to Product via OData urls
// eg: OData.svc/CategoryList(1)/ProductList(2) and so on
public IQueryable<Category> ProductList
{
get
{
return null;
}
}
}
[DataServiceKeyAttribute("CategoryId")]
public class Category
{
public int CategoryId { get; set; }
public string CategoryName { get; set; }
public List<Product> ProductList { get; set; }
}
[DataServiceKeyAttribute("ProductId")]
public class Product
{
public int ProductId { get; set; }
public string ProductName { get; set; }
}
据我所知,OData 将在幕后使用 LINQ 来查询这些内存中的对象,即:在这种情况下列出,如果有人导航到 OData.svc/CategoryList(1)/产品列表(2)等等。
但问题是:在现实世界场景中,我正在查看缓存内超过 1800 万条记录,代表超过 24 个不同的实体。
当前的生产 Web 服务很好地利用了 .NET Dictionary 和 Hashtable 集合来确保非常快速的查找并避免大量循环。因此,为了获取具有 CategoryID 1 的类别下具有 ProductID 2 的产品,当前的 Web 服务仅执行 2 次查找,即:第一个查找类别,第二个查找类别内的产品。像btree之类的东西。
我想知道如何遵循 OData 的类似架构,让 OData 和 LINQ 使用字典或哈希表来定位记录,而不是循环通用列表?
是否可以使用反射提供程序,或者我别无选择,只能为 OData 编写自定义提供程序?
提前致谢。
I am very new to OData (only started on it yesterday) so please excuse me if this question is too dumb :-)
I have built a test project as a Proof of Concept for migrating our current web services to OData. For this test project, I am using Reflection Providers to expose POCO classes via OData. These POCO classes come from in-memory cache. Below is the code so far:
public class DataSource
{
public IQueryable<Category> CategoryList
{
get
{
List<Category> categoryList = GetCategoryListFromCache();
return categoryList.AsQueryable();
}
}
// below method is only required to allow navigation
// from Category to Product via OData urls
// eg: OData.svc/CategoryList(1)/ProductList(2) and so on
public IQueryable<Category> ProductList
{
get
{
return null;
}
}
}
[DataServiceKeyAttribute("CategoryId")]
public class Category
{
public int CategoryId { get; set; }
public string CategoryName { get; set; }
public List<Product> ProductList { get; set; }
}
[DataServiceKeyAttribute("ProductId")]
public class Product
{
public int ProductId { get; set; }
public string ProductName { get; set; }
}
To the best of my knowledge, OData is going to use LINQ behind the scenes to query these in-memory objects, ie: List in this case if somebody navigates to OData.svc/CategoryList(1)/ProductList(2) and so on.
Here is the problem though: In the real world scenario, I am looking at over 18 million records inside the cache representing over 24 different entities.
The current production web services make very good use of .NET Dictionary and Hashtable collections to ensure very fast look ups and to avoid a lot of looping. So to get to a Product having ProductID 2 under Category having CategoryID 1, the current web services just do 2 look ups, ie: first one to locate the Category and the second one to locate the Product inside the Category. Something like a btree.
I wanted to know how could I follow a similar architecture with OData where I could tell OData and LINQ to use Dictionary or Hashtables for locating records rather than looping over a Generic List?
Is it possible using Reflection Providers or I am left with no other choice but to write my custom provider for OData?
Thanks in advance.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您将需要处理表达式树,因此您至少需要通过底层 LINQ to Objects 实现部分 IQueryable 实现。为此,您不需要完整的自定义提供程序,只需从上下文类的属性中返回 IQueryable 即可。
在该 IQueryable 中,您必须识别“关键”属性上的过滤器 (.Where(p => p.ProductID = 2)) 并将其转换为字典/哈希表查找。然后,您可以使用 LINQ to 对象来处理查询的其余部分。
但是,如果客户端发出带有不触及关键属性的过滤器的查询,则最终将进行全面扫描。不过,如果您选择这样做,您的自定义 IQueryable 可以检测到这一点并导致此类查询失败。
You will need to process expression trees, so you will need at least partial IQueryable implementation over the underlying LINQ to Objects. For this you don't need a full blown custom provider though, just return you IQueryable from the propties on the context class.
In that IQueryable you would have to recognize filters on the "key" properties (.Where(p => p.ProductID = 2)) and translate that into a dictionary/hashtable lookup. Then you can use LINQ to objects to process the rest of the query.
But if the client issues a query with filter which doesn't touch the key property, it will end up doing a full scan. Although, your custom IQueryable could detect that and fail such query if you choose so.