【问题标题】:Map Gremlin result containing string arrays to C# class containing simple string properties将包含字符串数组的 Gremlin 结果映射到包含简单字符串属性的 C# 类
【发布时间】:2020-06-29 03:12:26
【问题描述】:

在将 Gremlin 结果集映射到 C# 中的类时遇到问题。我正在尝试获取顶点和属性。代码如下:

public IList<T> All<T>() where T : class, new()
{
    Type type = typeof(T);
    string query = "g.V().hasLabel('" + type.Name.ToString().ToLower() + "').valueMap(true)";
    var resultSet = _gremlinClient.SubmitAsync<dynamic>(query).Result;
    List<T> list = JsonConvert.DeserializeObject<List<T>>(JsonConvert.SerializeObject(resultSet));
    return list;
}

这里是 User 实体,我将它传递给这个通用方法。

public class User
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Email { get; set; }
    public string Password { get; set; }
}

当我运行代码时,它在反序列化时抛出错误。

'解析值时遇到意外字符:[.路径“[0].FirstName”,第 1 行,位置 37。

当我检查它时,我发现 JSON 字符串的属性值带有方括号,如下所示:

[
  {
    "id": 0,
    "label": "user",
    "FirstName": [ "Azhar" ],
    "LastName": [ "Rahi" ]
  },
  {
    "id": 3,
    "label": "user",
    "FirstName": [ "John" ],
    "LastName": [ "Doe" ]
  }
]

您可以看到一些属性带有方括号,例如"FirstName":["Azhar"]。我已经在没有方括号的情况下对其进行了测试,并且工作正常。所以错误的原因是因为字符串在 JSON 中表示为数组。

在上述 JSON 字符串中,idlabel 是 Gremlin.Net 自动生成的属性。其余的实际上是User 对象属性。我不知道为什么 Gremlin 在向Vertex 添加属性时要添加括号,以及是否有可能避免它。

请提出任何解决方案,无论是在 Gremlin.Net 中还是通过某种方式更改 JSON 到类的映射。

【问题讨论】:

  • public string[] FirstName { get; set; }
  • 为什么要序列化和反序列化相同的东西,只返回resultSet
  • @Gusman 我知道,但逻辑上,用户的名字不能是数组。这样做将强制我从数组的索引 0 中获取值。第二,我使用的是通用方法,所以解决方案应该是通用的。我将更新我的描述。
  • @Sajid,这引发了其他错误。
  • 所以如果我理解正确的话,在resultSet 中你有一个名字和姓氏的数组,你可以序列化和反序列化以避免这个结果。如果是,你可以使用 JsonConverter。

标签: c# json.net gremlinnet


【解决方案1】:

所以,回顾一下:您有一些 JSON,其中一些属性是字符串数组,但您希望在您的类中将它们建模为单个字符串,因为数组应该始终只有一个值。

如您所见,默认情况下 Json.Net 不会处理此映射。但是您可以使用自定义JsonConverter 来弥补差距。像这样定义转换器:

public class ArrayToSingleStringConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(string);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JToken token = JToken.Load(reader);
        switch (token.Type)
        {
            case JTokenType.Array:
                return (string)token.Children<JValue>().FirstOrDefault();
            case JTokenType.String:
                return (string)token;
            case JTokenType.Null:
                return null;
            default:
                throw new JsonException("Unexpected token type: " + token.Type);
        }
    }

    public override bool CanWrite => false;

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

然后,对于类中的每个字符串属性(可能是 JSON 中的数组),添加一个 [JsonConverter] 属性,指定 ArrayToSingleStringConverter,如下所示:

public class User
{
    [JsonConverter(typeof(ArrayToSingleStringConverter))]
    public string FirstName { get; set; }

    [JsonConverter(typeof(ArrayToSingleStringConverter))]
    public string LastName { get; set; }
}

当您反序列化 JSON 时,它现在应该可以正常工作了。
演示小提琴:https://dotnetfiddle.net/Q9sGja

注意:如果您想以这种方式处理所有字符串属性,您可以将转换器传递给JsonConvert.DeserializeObject(),而不是使用[JsonConverter] 属性标记您的类:

List<T> list = JsonConvert.DeserializeObject<List<T>>(json, new ArrayToSingleStringConverter());

小提琴:https://dotnetfiddle.net/gcAqC5

【讨论】:

  • 好的,谢谢布赖恩。我也是这么想的。我会去的。但奇怪的是,为什么 Gremlin 用方括号设置属性值。它应该没有括号
  • 我不知道答案;我对 Gremlin 不是很熟悉。但我确实知道我在 Json.Net 中的使用方式,所以这就是我建议这个特殊解决方案的原因。
  • 是的,您的解决方案非常好。但我认为我需要使用反射来获取用户对象属性是否为数组。基于此,我必须将 json 对象属性设置为 User 对象属性
  • Json.Net 已经使用反射;这就是它的工作原理。除了我告诉你的之外,你不需要做任何额外的事情。使用转换器属性标记类中的字符串属性或将转换器传递给 DeserializeObject。转换器检查 JSON 中对应的属性是否为数组。如果是,则需要第一个孩子;否则它只是把它当作一个字符串。
  • 如果你说你的类有字符串数组(不是简单的字符串)并且相应的 JSON 属性有时是数组,有时是字符串,那么这是一个不同的问题,需要不同的转换器。见How to handle both a single item and an array for the same property using JSON.net。但这不是您在问题中所描述的。
猜你喜欢
  • 2020-04-20
  • 1970-01-01
  • 1970-01-01
  • 2021-07-20
  • 2018-05-22
  • 1970-01-01
  • 2014-10-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多