azure .NET CosmosDB NoSQL查询以匹配对象模型

z9ju0rcb  于 2023-04-12  发布在  .NET
关注(0)|答案(1)|浏览(111)

我是noSQL的新手,很难理解在调用时实际传递给T的构造函数的数据是什么

GetItemQueryIterator<T>(query).

我发现的大多数示例都使用了“SELECT * FROM mytable”,并且查询中使用的对象模型是myTable数据模式的完整表示,比如包括所有字段。
但是,如果我只想在一个特定的查询中从一个大表中选择几个字段呢?我需要有和许多不同查询一样多的数据模型类型吗?
更准确地说,让我们假设我在类似于下面的容器中有文档。我只对Body嵌套的JSON数据感兴趣,所有其他数据实际上都是在将数据馈送到CosmosDB时由Azure IoTHub推送的:

{
    "id": "fa14e6f9-b340-4b86-b7b2-46c58318bce5",
    "partitionKey": "VK_THC_Outside",
    "Properties": {},
    "SystemProperties": {
        "iothub-connection-device-id": "VK_THC_Outside",
        "iothub-connection-auth-method": "{\"scope\":\"device\",\"type\":\"sas\",\"issuer\":\"iothub\",\"acceptingIpFilterRule\":null}",
        "iothub-connection-auth-generation-id": "638151591628992733",
        "iothub-content-type": "application/json;charset=utf-8",
        "iothub-enqueuedtime": "2023-04-08T19:10:50.932Z",
        "iothub-message-source": "Telemetry"
    },
    "iothub-name": "lackoiothub",
    "Body": {
        "Temp": "3.30",
        "Hum": "91.30",
        "SBattery": "3532.00",
        "GBattery": "4466",
        "RSSI": "-48",
        "Version": "4",
        "TimeStamp": "2023-04-08T19:10:37Z"
    }
},

现在我不想建模或查询整个文档,只想使用这样的查询对其中的一部分进行建模或查询:

var query = new QueryDefinition(
  "SELECT i.Body.Temp, i.Body.Hum, i.Body.SBattery, i.Body.GBattery, i.Body.TimeStamp " +
  "FROM iothub i " +
  "WHERE i.partitionKey = \"VK_THC_Outside\" and i.Body.TimeStamp >= @minDate " +
  "ORDER BY i.Body.TimeStamp desc"
  ).WithParameter("@minDate", DateTime.Today);

我假设我会将字段返回为Temp,Hum,SBattery,GBattery和TimeStamp,因此我创建了一个模型对象:

public class SensorData
{
public string temp { get; set; } = "0";
public string hum { get; set; } = "0";
public string sbatt { get; set; } = "0";
public string gbatt { get; set; } = "0";
public DateTime time { get; set; }

public SensorData(string temp, string hum, string sbatt, string gbatt, string time)
{
  Debug.WriteLine($"Sensordata.ctor() : temp: {temp} hum: {hum} sbatt: {sbatt} gbatt: {gbatt} time: {time}");
  try
  {
    this.temp = temp;
    this.hum = hum;
    this.sbatt = sbatt;
    this.gbatt = gbatt;
    this.time = DateTime.Parse(time);
  }
  catch (Exception ex)
  {
    Debug.WriteLine($"Sensordata.ctor() : Exception : {ex.GetType().Name} {ex.Message}");
    this.time = DateTime.Now;
  }
}
}

把所有这些放在一起,我有下面的代码:

var query = new QueryDefinition(
  "SELECT i.Body.Temp, i.Body.Hum, i.Body.SBattery, i.Body.GBattery, i.Body.TimeStamp " +
  "FROM iothub i " +
  "WHERE i.partitionKey = \"VK_THC_Outside\" and i.Body.TimeStamp >= @minDate " +
  "ORDER BY i.Body.TimeStamp desc"
  ).WithParameter("@minDate", DateTime.Today);

  using FeedIterator<SensorData> feed = container.GetItemQueryIterator<SensorData>(query);

  while (feed.HasMoreResults)
  {
    var sData = await feed.ReadNextAsync();
    sData.ForEach(d => _sensorsData.Add(d));
  }

结果这不起作用,我没有得到或奇怪的数据传递到SensorData构造函数。感谢调试消息,我可以看到数据没有按预期传递。没有数据传递给SensorData的构造函数参数sbatt,gbatt和time:

Sensordata.ctor() : Exception : ArgumentNullException Value cannot be null. (Parameter 's')
Sensordata.ctor() : temp: 3.50 hum: 91.30 sbatt:  gbatt:  time: 
Exception thrown: 'System.ArgumentNullException' in System.Private.CoreLib.dll
Sensordata.ctor() : Exception : ArgumentNullException Value cannot be null. (Parameter 's')
Sensordata.ctor() : temp: 3.50 hum: 91.20 sbatt:  gbatt:  time: 
Exception thrown: 'System.ArgumentNullException' in System.Private.CoreLib.dll
Sensordata.ctor() : Exception : ArgumentNullException Value cannot be null. (Parameter 's')
Sensordata.ctor() : temp: 3.60 hum: 91.20 sbatt:  gbatt:  time: 
Exception thrown: 'System.ArgumentNullException' in System.Private.CoreLib.dll
Sensordata.ctor() : Exception : ArgumentNullException Value cannot be null. (Parameter 's')
Sensordata.ctor() : temp: 3.60 hum: 91.10 sbatt:  gbatt:  time: 
Exception thrown: 'System.ArgumentNullException' in System.Private.CoreLib.dll
Sensordata.ctor() : Exception : ArgumentNullException Value cannot be null. (Parameter 's')

因此,我找到了另一种方法,首先避免反序列化,并检查查询实际返回的是什么数据。为此,我用GetItemQueryStreamIterator替换了通用的GetItemQueryIterator,并使用下面的代码处理相同的查询:

using FeedIterator feed = container.GetItemQueryStreamIterator(query);

  while (feed.HasMoreResults)
  {
    var response = await feed.ReadNextAsync();
    using (StreamReader sr = new StreamReader(response.Content))
    using (JsonTextReader jtr = new JsonTextReader(sr))
    {
      JObject result = JObject.Load(jtr);
    }

在上面的循环中检查变量“result”的值,我现在可以看到实际上查询结果与预期的一样:

所以谁能给我指个方向为什么

container.GetItemQueryIterator<SensorData>(query)

没有按预期工作吗

wkyowqbh

wkyowqbh1#

您需要荣誉属性的大写或使用装饰器来分配哪个Json属性与哪个类属性匹配。
第一个是最简单的一个:

public class SensorData
{
public string Temp { get; set; } = "0";
public string Hum { get; set; } = "0";
public string SBattery { get; set; } = "0";
public string GBattery { get; set; } = "0";
public DateTime TimeStamp { get; set; }
}

也可以使用JObject

container.GetItemQueryIterator<JObject>(query)

并使用JObject访问器(如item["Hum"])获取Hum属性值。

相关问题