Microsoft.Azure.Graphs:如何将Gremlin查询结果转换为指定类型?
嘿,我之前在做.NET对接Gremlin的时候也遇到过这个问题——默认返回的dynamic结构确实有点绕,不过有几种实用的方法能把它转换成你想要的强类型,我给你详细说说:
方法1:手动映射(适合简单场景)
如果你的实体类结构不复杂,直接手动把dynamic里的字段对应到实体属性是最直接的方式。
首先先定义你的目标实体类,比如Person:
public class Person { public string Id { get; set; } public string Label { get; set; } public string FirstName { get; set; } public int? Age { get; set; } // 用可空类型处理可能缺失的属性 }
然后遍历查询结果,逐个赋值:
var personList = new List<Person>(); IDocumentQuery<dynamic> query = client.CreateGremlinQuery<dynamic>(graph, "g.V().hasLabel('person')"); while (query.HasMoreResults) { foreach (var vertex in await query.ExecuteNextAsync()) { var person = new Person { Id = vertex.id, Label = vertex.label, // Gremlin返回的properties是数组,取第一个元素的value FirstName = vertex.properties.firstName[0].value, Age = vertex.properties.age?[0].value // 加问号处理age属性不存在的情况 }; personList.Add(person); } }
方法2:用序列化库自动映射(优雅的长期方案)
如果实体类较多或者属性复杂,手动映射太麻烦,可以用Newtonsoft.Json(或者System.Text.Json)来做自动转换,甚至可以写自定义转换器适配Gremlin的返回结构。
方式2.1:直接解析JObject
using Newtonsoft.Json.Linq; var personList = new List<Person>(); IDocumentQuery<dynamic> query = client.CreateGremlinQuery<dynamic>(graph, "g.V().hasLabel('person')"); while (query.HasMoreResults) { foreach (var vertex in await query.ExecuteNextAsync()) { var jVertex = JObject.FromObject(vertex); var person = new Person { Id = jVertex["id"].ToString(), Label = jVertex["label"].ToString(), FirstName = jVertex["properties"]["firstName"][0]["value"].ToString(), Age = jVertex["properties"]["age"]?[0]["value"].ToObject<int?>() }; personList.Add(person); } }
方式2.2:自定义JsonConverter(复用性更强)
写一个专门处理Gremlin顶点结构的转换器,以后所有实体类都能复用:
using Newtonsoft.Json; using Newtonsoft.Json.Linq; public class GremlinVertexConverter<T> : JsonConverter<T> where T : new() { public override T ReadJson(JsonReader reader, Type objectType, T existingValue, bool hasExistingValue, JsonSerializer serializer) { var jObject = JObject.Load(reader); var entity = new T(); // 映射基础字段:id和label var idProp = objectType.GetProperty("Id"); if (idProp != null) idProp.SetValue(entity, jObject["id"].ToString()); var labelProp = objectType.GetProperty("Label"); if (labelProp != null) labelProp.SetValue(entity, jObject["label"].ToString()); // 映射properties里的自定义字段 var properties = jObject["properties"] as JObject; if (properties != null) { foreach (var prop in properties) { var entityProp = objectType.GetProperty(prop.Key, System.Reflection.BindingFlags.IgnoreCase | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); if (entityProp != null) { var value = prop.Value[0]["value"]; if (value != null) { var convertedValue = Convert.ChangeType(value, entityProp.PropertyType); entityProp.SetValue(entity, convertedValue); } } } } return entity; } public override void WriteJson(JsonWriter writer, T value, JsonSerializer serializer) { // 如果需要把实体转成Gremlin格式,可以在这里实现,一般查询场景用不到 throw new NotImplementedException(); } }
使用的时候只需要配置序列化器:
var settings = new JsonSerializerSettings(); settings.Converters.Add(new GremlinVertexConverter<Person>()); var personList = new List<Person>(); IDocumentQuery<dynamic> query = client.CreateGremlinQuery<dynamic>(graph, "g.V().hasLabel('person')"); while (query.HasMoreResults) { foreach (var vertex in await query.ExecuteNextAsync()) { var person = JsonConvert.DeserializeObject<Person>(vertex.ToString(), settings); personList.Add(person); } }
方法3:修改Gremlin查询返回扁平结构(最省心)
如果有权限修改Gremlin查询语句,直接用project步骤把顶点的属性转成扁平的键值对,这样返回的dynamic结构和你的实体类完全匹配,转换起来毫无压力。
修改后的Gremlin查询:
g.V().hasLabel('person') .project('id', 'label', 'firstName', 'age') .by(id()) .by(label()) .by('firstName') .by('age')
这时候返回的结果格式会变成:
{"id":"thomas","label":"person","firstName":"Thomas","age":44}
然后转换代码就超级简单了:
var personList = new List<Person>(); IDocumentQuery<dynamic> query = client.CreateGremlinQuery<dynamic>(graph, "g.V().hasLabel('person').project('id','label','firstName','age').by(id()).by(label()).by('firstName').by('age')"); while (query.HasMoreResults) { foreach (var item in await query.ExecuteNextAsync()) { var person = new Person { Id = item.id, Label = item.label, FirstName = item.firstName, Age = item.age }; personList.Add(person); } }
内容的提问来源于stack exchange,提问作者Stef Heyenrath
相关产品推荐
相关产品推荐

