C# IEnumerable<;IDictionary<;字符串,对象>&燃气轮机;可食用

C# IEnumerable<;IDictionary<;字符串,对象>&燃气轮机;可食用,c#,linq,datatable,odata,C#,Linq,Datatable,Odata,我有一个应用程序,它允许用户动态查询任何OData服务,并返回他们在网格中请求的特定列。经过几周的研究,我最终用它来查询服务。为了得到数据,我有一个模型来定义需要做什么。以下是与我的问题相关的内容: BaseUrl(服务地址) ListName(要查询的表/列表) 列(列表) ODataColumnPath(指向所需数据的路径) ColumnDataType(返回/转换到的数据类型) FriendlyName(友好使用的东西) 计算类型(枚举无、计数、求和、最小值、最大值) 现在,ODa

我有一个应用程序,它允许用户动态查询任何OData服务,并返回他们在网格中请求的特定列。经过几周的研究,我最终用它来查询服务。为了得到数据,我有一个模型来定义需要做什么。以下是与我的问题相关的内容:

  • BaseUrl(服务地址)
  • ListName(要查询的表/列表)
  • 列(列表)
    • ODataColumnPath(指向所需数据的路径)
    • ColumnDataType(返回/转换到的数据类型)
    • FriendlyName(友好使用的东西)
    • 计算类型(枚举
      无、计数、求和、最小值、最大值
现在,
ODataColumnPath
可以像“ProductName”一样简单,也可以像“Category/Product/Orders/OrderID”一样复杂,以返回单个字段或多个字段。当它返回许多值时,我用它进行某种计算

目前,我通过递归(while loop)遍历所有
IEnumerable
s创建了一个
DataTable
,直到得到我要查找的值。然后,我使用XML数据创建DataTable列,然后从循环中填充行。这种方法很好,但我认为有更好的方法

现在,当我在LinqPad中运行直接连接到的查询时,我返回一个
IQueryable?$expand=Category&$select=ProductID、ProductName、Category/CategoryName

使用上面提到的OData库,我返回的数据与
IEnumerable

代码

ODataClient client = new ODataClient(new ODataClientSettings { UrlBase = "http://demos.telerik.com/kendo-ui/service/Northwind.svc/", OnTrace = (a, b) => { string.Format(a, b).Dump("Trace Event"); } });
var data = await client.For("Products").Expand("Category").Select("ProductID,ProductName,Category/CategoryName").FindEntriesAsync().Dump();
请求URL(来自跟踪事件)

?$expand=Category&$select=ProductID、ProductName、Category/CategoryName

现在,如果我指定了一个强类型的类,我会得到与
IQueryable
相同的结果(需要做一些额外的工作):

var强=(等待客户端)
.对于()
.Expand(x=>x.Category)
.Select(x=>new{x.ProductID,x.ProductName,x.Category.CategoryName})
.FindEntriesAsync())
.Select(x=>new{x.ProductID,x.ProductName,x.Category.CategoryName})
.Dump();
我想得到的是匿名列表对象或动态对象。从那里我可以应用我的计算,如果需要的话。是否有一种方法可以动态定义一个类并将其传递到(…)的
静态方法中

尽管我花了数周时间研究这个主题,最终使用Simple.OData.Client,但我还是愿意使用其他方法来获取数据。

我最终找到了一个从字典中创建匿名对象的方法来创建匿名对象。 最后,我用以下代码修改了第一个
CreateObject
方法

public static object CreateObject(IDictionary<string, object> valueDictionary)
{
  Dictionary<string, object> values = new Dictionary<string, object>();

  foreach (KeyValuePair<string, object> pair in valueDictionary)
  {
      if (pair.Value != null && pair.Value.GetType() == typeof(Dictionary<string, object>))
      {
          // Create object and add
          object o = CreateObject(pair.Value as IDictionary<string, object>);
          values.Add(pair.Key, o);
      }
      else if (pair.Value != null && pair.Value.GetType() == typeof(List<IDictionary<string, object>>))
      {
          // Get first dictionary entry
          IDictionary<string, object> firstDictionary = ((IEnumerable<IDictionary<string, object>>)pair.Value).First();

          // Get the base object
          object baseObject = CreateObject(firstDictionary);

          // Create a new array based off of the base object
          Array anonArray = Array.CreateInstance(baseObject.GetType(), 1);

          // Return like the others
          values.Add(pair.Key, anonArray);
      }
      else
      {
          values.Add(pair.Key, pair.Value);
      }
  }

  Dictionary<string, Type> typeDictionary = values.ToDictionary(kv => kv.Key, kv => kv.Value != null ? kv.Value.GetType() : typeof(object));

  Type anonymousType = CreateType(typeDictionary);

  return CreateObject(values, anonymousType);
}
我可能会创建一个Simple.OData.Client分支,并将其添加到其中,这样我就不必将对象序列化回JSON,然后再序列化回对象

var strongly = (await client
    .For<Product>()
    .Expand(x => x.Category)
    .Select(x => new { x.ProductID, x.ProductName, x.Category.CategoryName })
    .FindEntriesAsync())
    .Select(x => new { x.ProductID, x.ProductName, x.Category.CategoryName })
    .Dump();
public static object CreateObject(IDictionary<string, object> valueDictionary)
{
  Dictionary<string, object> values = new Dictionary<string, object>();

  foreach (KeyValuePair<string, object> pair in valueDictionary)
  {
      if (pair.Value != null && pair.Value.GetType() == typeof(Dictionary<string, object>))
      {
          // Create object and add
          object o = CreateObject(pair.Value as IDictionary<string, object>);
          values.Add(pair.Key, o);
      }
      else if (pair.Value != null && pair.Value.GetType() == typeof(List<IDictionary<string, object>>))
      {
          // Get first dictionary entry
          IDictionary<string, object> firstDictionary = ((IEnumerable<IDictionary<string, object>>)pair.Value).First();

          // Get the base object
          object baseObject = CreateObject(firstDictionary);

          // Create a new array based off of the base object
          Array anonArray = Array.CreateInstance(baseObject.GetType(), 1);

          // Return like the others
          values.Add(pair.Key, anonArray);
      }
      else
      {
          values.Add(pair.Key, pair.Value);
      }
  }

  Dictionary<string, Type> typeDictionary = values.ToDictionary(kv => kv.Key, kv => kv.Value != null ? kv.Value.GetType() : typeof(object));

  Type anonymousType = CreateType(typeDictionary);

  return CreateObject(values, anonymousType);
}
// Get Data
ODataClient client = new ODataClient(new ODataClientSettings { UrlBase = "http://demos.telerik.com/kendo-ui/service/Northwind.svc/", OnTrace = (a, b) => { string.Format(a, b).Dump("Trace Event"); } });
IEnumerable<IDictionary<string, object>> data = await client
    .For("Products")
    .Expand("Category,Order_Details")
    .Select("ProductID,ProductName,SupplierID,CategoryID,QuantityPerUnit,UnitPrice,UnitsInStock,UnitsOnOrder,ReorderLevel,Discontinued,Category/CategoryName,Order_Details")
    .FindEntriesAsync();

// Convert to JSON
string json = JsonConvert.SerializeObject(data);

// Create anonymous type/object
object anonymousObject = AnonymousClassBuilder.CreateObject(data.First());

// Deserialize into type
IEnumerable enumerable = (IEnumerable)JsonConvert.DeserializeObject(json, anonymousObject.GetType().MakeArrayType());